首先这个叫"动态点分治",不过瞎YY也能YY出来【比如我。。。
就是记录下点分治的过程和每个点的答案信息,于是查询的时候只要沿着分治好的根一路走下去就行了,于是单次查询的外层复杂度是$O(log n)$的
对于每个点,要记录以从整棵树到它的分治路径和以它为根的子树内权值小于v的点到它的距离和(就是关于权值的前缀和)
于是查询一个点的时候只要二分一下就好了。。。
总复杂度$O((n + Q) * log^2n)$
写了一晚上QAQQQ
1 /************************************************************** 2 Problem: 4012 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:28756 ms 7 Memory:107560 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <algorithm> 12 #include <vector> 13 14 using namespace std; 15 typedef long long ll; 16 const int N = 15e4 + 4; 17 18 inline int read(); 19 inline void print(ll); 20 21 struct edge { 22 int next, to, v; 23 edge(int _n = 0, int _t = 0, int _v = 0) : next(_n), to(_t), v(_v) {} 24 } e[N << 1]; 25 26 struct data { 27 int v; 28 ll dis; 29 data(int _v = 0, ll _d = 0) : v(_v), dis(_d) {} 30 31 inline bool operator < (const data &p) const { 32 return v == p.v ? dis < p.dis : v < p.v; 33 } 34 }; 35 36 struct Path { 37 int p, s; 38 ll dis; 39 Path(int _p = 0, ll _d = 0, int _s = 0) : p(_p), dis(_d), s(_s) {} 40 }; 41 42 struct tree_node { 43 int v, sz, mx, vis; 44 vector <Path> path; 45 vector <data> dis[3]; 46 } tr[N]; 47 48 int n, m, mod; 49 int size, root; 50 int first[N], tot; 51 int L, R; 52 ll ans; 53 54 inline void Add_Edges(int x, int y, int z) { 55 e[++tot] = edge(first[x], y, z), first[x] = tot; 56 e[++tot] = edge(first[y], x, z), first[y] = tot; 57 } 58 59 #define y e[x].to 60 void get_sz(int p, int fa) { 61 int x; 62 tr[p].sz = 1; 63 for (x = first[p]; x; x = e[x].next) 64 if (!tr[y].vis && y != fa) { 65 get_sz(y, p); 66 tr[p].sz += tr[y].sz; 67 } 68 } 69 70 void get_rt(int p, int fa) { 71 int x; 72 tr[p].sz = 1, tr[p].mx = 0; 73 for (x = first[p]; x; x = e[x].next) 74 if (!tr[y].vis && y != fa) { 75 get_rt(y, p); 76 tr[p].sz += tr[y].sz; 77 tr[p].mx = max(tr[p].mx, tr[y].sz); 78 } 79 tr[p].mx = max(tr[p].mx, size - tr[p].sz); 80 if (tr[p].mx < tr[root].mx) root = p; 81 } 82 83 void calc(int p, int fa, int tar, int d, int now) { 84 int x; 85 tr[p].path.push_back(Path(tar, d, now)); 86 tr[tar].dis[now].push_back(data(tr[p].v, d)); 87 for (x = first[p]; x; x = e[x].next) 88 if (!tr[y].vis && y != fa) 89 calc(y, p, tar, d + e[x].v, now); 90 } 91 92 void work(int p) { 93 int x, now = 0; 94 tr[p].vis = 1; 95 get_sz(p, 0); 96 tr[p].path.push_back(Path(p, 0, 3)); 97 for (x = first[p]; x; x = e[x].next) 98 if (!tr[y].vis) calc(y, p, p, e[x].v, now++); 99 for (x = first[p]; x; x = e[x].next) 100 if (!tr[y].vis) { 101 root = 0, size = tr[y].sz; 102 get_rt(y, 0); 103 work(root); 104 } 105 } 106 #undef y 107 108 inline ll query(vector <data> *v, ll d, int s) { 109 static ll res; 110 static int i, t; 111 for (i = res = 0; i < 3; ++i) if (i != s) { 112 t = lower_bound(v[i].begin(), v[i].end(), data(L, -1)) - v[i].begin(); 113 if (t) res -= d * t + v[i][t - 1].dis; 114 t = lower_bound(v[i].begin(), v[i].end(), data(R + 1, -1)) - v[i].begin(); 115 if (t) res += d * t + v[i][t - 1].dis; 116 } 117 return res; 118 } 119 120 int main() { 121 int i, j, k, x, y, z, Q, p; 122 n = read(), Q = read(), mod = read(); 123 for (i = 1; i <= n; ++i) tr[i].v = read(); 124 for (i = 1; i < n; ++i) { 125 x = read(), y = read(), z = read(); 126 Add_Edges(x, y, z); 127 } 128 tr[root = 0].mx = size = n; 129 get_rt(1, 0); 130 work(root); 131 for (i = 1; i <= n; ++i) 132 for (j = 0; j < 3; ++j) { 133 sort(tr[i].dis[j].begin(), tr[i].dis[j].end()); 134 for (k = 1; k < tr[i].dis[j].size(); ++k) 135 tr[i].dis[j][k].dis += tr[i].dis[j][k - 1].dis; 136 } 137 for (ans = 0; Q; --Q) { 138 p = read(), L = (ans + read()) % mod, R = (ans + read()) % mod; 139 if (L > R) swap(L, R); 140 for (i = ans = 0; i < tr[p].path.size(); ++i) { 141 if (L <= tr[tr[p].path[i].p].v && tr[tr[p].path[i].p].v <= R) 142 ans += tr[p].path[i].dis; 143 ans += query(tr[tr[p].path[i].p].dis, tr[p].path[i].dis, tr[p].path[i].s); 144 } 145 print(ans); 146 } 147 return 0; 148 } 149 150 inline int read() { 151 static int x; 152 static char ch; 153 x = 0, ch = getchar(); 154 while (ch < '0' || '9' < ch) 155 ch = getchar(); 156 while ('0' <= ch && ch <= '9') { 157 x = x * 10 + ch - '0'; 158 ch = getchar(); 159 } 160 return x; 161 } 162 163 inline void print(ll t) { 164 static int tot, pr[20]; 165 tot = 0; 166 while (t) 167 pr[++tot] = t % 10, t /= 10; 168 if (!tot) putchar('0'); 169 while (tot) putchar(pr[tot--] + '0'); 170 putchar(' '); 171 }
(p.s. bz上AC700T纪念!)