题意:紫妹和幽香是17岁的少女,喜欢可爱的东西。
给定一棵树,有点权,边权。每次求所有权值在[l, r]范围内的点到点x的距离和。强制在线。
解:动态点分治怎么搞啊......
一开始想的是权值的限制直接外层权值线段树就行了,关键是怎么批量求距离。
jxl想的是树上莫队的方法,括号序列。然后发现当x和y在不同子树的时候,x -> lca的距离是负的。
然后考虑lca。距离是d[x] + d[y] - 2d[lca],前面两个都好求,主要是第三项。
稍稍思考一下,lca只可能是x到根路径上的点。每个点作为lca的次数就是siz - siz[son]
所以可以转为计算每条边的贡献。每条边的贡献就是它下面的子树大小。这样就可以做了。
具体来说,d[x] * cnt和∑d[y]可以用两个前缀和数组求出。以离散化后的权值为下标。
然后建一个以权值为版本的主席树,线段树上维护的是DFS序的该点的父边的计算次数。
可以发现,按照权值我们每插入一个点,就要对它到根的路径进行修改。查询的时候也是查询x到根的路径。所以我们必须写树剖了>_<
主席树区间加区间查,使用标记永久化。
然后发现我之前以为的标记永久化都是假的......
具体来说,给一个区间加的时候,它途中经过的区间都要加上相应的值,而标记只打在最后的区间。
查询的时候,沿途记录标记数量。到终点的时候,用终点的sum + 区间Val * 标记数量即可。
如果修改在查询上面,那么你会把标记记录下来,最后在终点区间加上。
如果修改在下,那么你终点区间的sum已经加了那一次修改的影响。
然后这道毒瘤SB题就这样A了...时间复杂度nlog2n。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <cstdio> 2 #include <algorithm> 3 4 typedef long long LL; 5 const int N = 150010, lm = 1e9, M = 30000010; 6 7 struct Edge { 8 int nex, v, len; 9 }edge[N << 1]; int tp; 10 11 struct Node { 12 int val, p; 13 inline bool operator <(const Node &w) const { 14 return val < w.val; 15 } 16 }node[N]; 17 18 int e[N], n, top[N], son[N], fa[N], pos[N], num, siz[N], X[N], deep[N], Sum[N], id[N], val2[N], tot, rt[N], val[N]; 19 LL Val[M], d[N], exVal[N]; 20 int ls[M], rs[M], exsum[N], tag[M]; 21 22 inline void add(int x, int y, int z) { 23 tp++; 24 edge[tp].v = y; 25 edge[tp].len = z; 26 edge[tp].nex = e[x]; 27 e[x] = tp; 28 return; 29 } 30 31 void DFS_1(int x, int f) { // siz fa d son 32 fa[x] = f; 33 siz[x] = 1; 34 deep[x] = deep[f] + 1; 35 for(int i = e[x]; i; i = edge[i].nex) { 36 int y = edge[i].v; 37 if(y == f) { 38 continue; 39 } 40 d[y] = d[x] + edge[i].len; 41 val2[y] = edge[i].len; 42 DFS_1(y, x); 43 siz[x] += siz[y]; 44 if(siz[y] > siz[son[x]]) { 45 son[x] = y; 46 } 47 } 48 return; 49 } 50 51 void DFS_2(int x, int f) { // pos top 52 top[x] = f; 53 pos[x] = ++num; 54 id[num] = x; 55 if(son[x]) { 56 DFS_2(son[x], f); 57 } 58 for(int i = e[x]; i; i = edge[i].nex) { 59 int y = edge[i].v; 60 if(y == fa[x] || y == son[x]) { 61 continue; 62 } 63 DFS_2(y, y); 64 } 65 return; 66 } 67 68 void Add(int x, int &y, int L, int R, int l, int r) { 69 if(!y || y == x) { 70 y = ++tot; 71 Val[y] = Val[x]; 72 tag[y] = tag[x]; 73 ls[y] = ls[x]; 74 rs[y] = rs[x]; 75 //printf("new %d [%d %d] val = %lld \n", y, l, r, Val[y]); 76 } 77 Val[y] += Sum[std::min(R, r)] - Sum[std::max(L, l) - 1]; 78 //printf("val %d = %lld += (%d %d) %d \n", y, Val[y], std::min(R, r), std::max(L, l) - 1, Sum[std::min(R, r)] - Sum[std::max(L, l) - 1]); 79 if(L <= l && r <= R) { 80 tag[y]++; 81 return; 82 } 83 int mid = (l + r) >> 1; 84 if(L <= mid) { 85 Add(ls[x], ls[y], L, R, l, mid); 86 } 87 if(mid < R) { 88 Add(rs[x], rs[y], L, R, mid + 1, r); 89 } 90 return; 91 } 92 93 inline void insert(int x, int id) { 94 while(x) { 95 //printf("id = %d \n", id); 96 Add(rt[id - 1], rt[id], pos[top[x]], pos[top[x]] + (deep[x] - deep[top[x]]), 1, n); 97 x = fa[top[x]]; 98 } 99 return; 100 } 101 102 LL Ask(int x, int y, int L, int R, int l, int r, int tagx, int tagy) { 103 if(L <= l && r <= R) { 104 return Val[y] - Val[x] + 1ll * (tagy - tagx) * (Sum[r] - Sum[l - 1]); 105 } 106 tagx += tag[x]; 107 tagy += tag[y]; 108 int mid = (l + r) >> 1; 109 LL ans = 0; 110 if(L <= mid) { 111 ans += Ask(ls[x], ls[y], L, R, l, mid, tagx, tagy); 112 } 113 if(mid < R) { 114 ans += Ask(rs[x], rs[y], L, R, mid + 1, r, tagx, tagy); 115 } 116 return ans; 117 } 118 119 LL ask(int l, int r, int x) { 120 LL ans = 0; 121 while(x) { 122 LL t = Ask(rt[l - 1], rt[r], pos[top[x]], pos[top[x]] + (deep[x] - deep[top[x]]), 1, n, 0, 0); 123 ans += t; 124 x = fa[top[x]]; 125 } 126 return ans; 127 } 128 129 int main() { 130 131 //freopen("in.in", "r", stdin); 132 //freopen("my.out", "w", stdout); 133 134 int q, A; 135 scanf("%d%d%d", &n, &q, &A); 136 for(int i = 1; i <= n; i++) { 137 scanf("%d", &val[i]); 138 val[i]++; 139 node[i].p = i; 140 X[i] = val[i]; 141 } 142 for(int i = 1, x, y, z; i < n; i++) { 143 scanf("%d%d%d", &x, &y, &z); 144 add(x, y, z); 145 add(y, x, z); 146 } 147 // prework 148 149 DFS_1(1, 0); 150 DFS_2(1, 1); 151 std::sort(X + 1, X + n + 1); 152 int temp = std::unique(X + 1, X + n + 1) - X - 1; 153 for(int i = 1; i <= n; i++) { 154 val[i] = std::lower_bound(X + 1, X + temp + 1, val[i]) - X; 155 node[i].val = val[i]; 156 exsum[val[i]]++; 157 exVal[val[i]] += d[i]; 158 } 159 for(int i = 1; i <= temp; i++) { 160 exsum[i] += exsum[i - 1]; 161 exVal[i] += exVal[i - 1]; 162 } 163 for(int i = 1; i <= n; i++) { 164 Sum[i] = Sum[i - 1] + val2[id[i]]; 165 } 166 std::sort(node + 1, node + n + 1); 167 for(int i = 1; i <= n; i++) { 168 insert(node[i].p, node[i].val); 169 } 170 171 LL lastans = 0; 172 for(int i = 1, x, y, z; i <= q; i++) { 173 scanf("%d%d%d", &x, &y, &z); 174 int l = (y + lastans) % A + 1; 175 int r = (z + lastans) % A + 1; 176 if(l > r) { 177 std::swap(l, r); 178 } 179 l = std::lower_bound(X + 1, X + temp + 1, l) - X; 180 r = std::upper_bound(X + 1, X + temp + 1, r) - X - 1; 181 if(l > r) { 182 lastans = 0; 183 printf("%lld\n", lastans); 184 } 185 else { 186 LL t = ask(l, r, x); 187 lastans = 1ll * d[x] * (exsum[r] - exsum[l - 1]) + (exVal[r] - exVal[l - 1]); 188 lastans -= t * 2; 189 printf("%lld\n", lastans); 190 } 191 } 192 193 return 0; 194 }