树上莫队

首先有一道题

王室联邦

题目大意

给定一棵树,将树分为大小范围为 $[B, 3B]$ 的连通块集,求方案

树上分块方法之一

类似贪心,用栈维护还没有在连通块中的子节点,对于递归到的当前的点 $p$ ,扫描它的子树,能拼凑就拼凑

但是注意最后可能还会有一些点(一定包括根)剩下,那么将这些点并到最后一个连通块即可

显然每个连通块都满足大小为 $[B, 3B]$

核心代码
void DFS (int root, int father) {
    int bot = top;
    for (int i = Head[root]; i; i = Link[i].next) {
        int v = Link[i].to;
        if (v == father)
            continue;
        DFS (v, root);
        if (top - bot >= B) {
            capt[++ bind] = root;
            while (top > bot)
                belong[Stack[top --]] = bind;
        }
    }
    Stack[++ top] = root;
}

树上莫队

首先用王室联邦的方法将树分块

用一个数组 $state_p$ 来维护 $p$ 点是否在当前询问的路径上,那么每次访问就将 $state_p$ 翻转,顺便修改 $ans$ ,相当于原序列上莫队的 $add, del$ 操作

那么,每次需要修改那些点呢?

假设当前处理到 $(px, py)$ ,现在需要处理 $(x, y)$ ,那么只需修改 $px$ 到 $x$ 以及 $py$ 到 $y$ 的路径上的点即可

接下来证明该操作的正确性:

令 $T (x, y)$ 表示 $x$ 到 $y$ 路径上的点集, $xor$ 操作类似位运算的异或,即有相同点则删去,无则加入

则有 $T (x, y) = T (x, root) xor T (y, root)$ (注意,这里的 $T (x, y)$ 是不包括 $lca$ 的,故 $lca$ 需单独处理

接下来是证明

$\begin{aligned} &T (px, py) \ xor \ T (x, y) \\ &= [T (px, root) \ xor \ T (py, root)] \ xor \ [T (x, root) \ xor \ T (y, root)] \\ &=  [T (px, root) \ xor \ T (x, root)] \ xor \ [T (py, root) \ xor \ T (y, root)] \\ &= T (px, x) \ xor \ T (py, y) \end{aligned}$

那么其它的修改什么的就和序列上莫队一样了

例题

[WC2013]糖果公园

代码

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 
  7 using namespace std;
  8 
  9 typedef long long LL;
 10 
 11 const int MAXN = 1e05 + 10;
 12 const int MAXM = 1e05 + 10;
 13 const int MAXQ = 1e05 + 10;
 14 
 15 struct LinkedForwardStar {
 16     int to;
 17 
 18     int next;
 19 } ;
 20 
 21 LinkedForwardStar Link[MAXM << 1];
 22 int Head[MAXN]= {0};
 23 int size = 0;
 24 
 25 void Insert (int u, int v) {
 26     Link[++ size].to = v;
 27     Link[size].next = Head[u];
 28 
 29     Head[u] = size;
 30 }
 31 
 32 int N, M, Q;
 33 LL V[MAXN], W[MAXN];
 34 int pcol[MAXN];
 35 int limit;
 36 
 37 int belong[MAXN];
 38 int lind = 0;
 39 int Stack[MAXN];
 40 int top = 0;
 41 void DFS_bel (int root, int father) {
 42     int bot = top;
 43     for (int i = Head[root]; i; i = Link[i].next) {
 44         int v = Link[i].to;
 45         if (v == father)
 46             continue;
 47         DFS_bel (v, root);
 48         if (top - bot >= limit) {
 49             lind ++;
 50             while (top > bot)
 51                 belong[Stack[top --]] = lind;
 52         }
 53     }
 54     Stack[++ top] = root;
 55 }
 56 
 57 int father[MAXN]= {0};
 58 int deep[MAXN];
 59 int dfn[MAXN];
 60 int value[MAXN << 1], ranking[MAXN << 1];
 61 int dfsord = 0;
 62 void DFS_LCA (int root, int fa) {
 63     father[root] = fa;
 64     dfn[root] = ++ dfsord;
 65     value[dfsord] = deep[root], ranking[dfsord] = root;
 66     for (int i = Head[root]; i; i = Link[i].next) {
 67         int v = Link[i].to;
 68         if (v == fa)
 69             continue;
 70         deep[v] = deep[root] + 1;
 71         DFS_LCA (v, root);
 72         value[++ dfsord] = deep[root], ranking[dfsord] = root;
 73     }
 74 }
 75 pair<int, int> ST[MAXN << 1][20];
 76 void RMQ () {
 77     for (int i = 1; i <= dfsord; i ++)
 78         ST[i][0] = make_pair (value[i], ranking[i]);
 79     for (int j = 1; j <= 18; j ++)
 80         for (int i = 1; i + (1 << j) - 1 <= dfsord; i ++)
 81             ST[i][j] = ST[i][j - 1].first < ST[i + (1 << (j - 1))][j - 1].first ? ST[i][j - 1] : ST[i + (1 << (j - 1))][j - 1];
 82 }
 83 int LCA (int x, int y) {
 84     int L = dfn[x], R = dfn[y];
 85     if (L > R)
 86         swap (L, R);
 87     int k = log2 (R - L + 1);
 88     return ST[L][k].first < ST[R - (1 << k) + 1][k].first ? ST[L][k].second : ST[R - (1 << k) + 1][k].second;
 89 }
 90 
 91 LL ans = 0;
 92 
 93 struct QuerySt {
 94     int index;
 95     int time;
 96     int x, y;
 97 
 98     QuerySt (int find = 0, int ftime = 0, int fx = 0, int fy = 0) :
 99         index (find), time (ftime), x (fx), y (fy) {}
100 
101     bool operator < (const QuerySt& p) const {
102         if (belong[x] != belong[p.x])
103             return belong[x] < belong[p.x];
104         if (belong[y] != belong[p.y])
105             return belong[y] < belong[p.y];
106         return time < p.time;
107     }
108 } ;
109 QuerySt Query[MAXQ];
110 int qind = 0;
111 int modposi[MAXQ], modtime[MAXQ];
112 int modpre[MAXQ], modval[MAXQ];
113 int mind = 0, cur = 0;
114 int state[MAXN]= {0};
115 int donet[MAXN]= {0};
116 void reverse (int p) {
117     if (state[p])
118         ans -= V[pcol[p]] * W[donet[pcol[p]]], donet[pcol[p]] --;
119     state[p] ^= 1;
120     if (state[p])
121         donet[pcol[p]] ++, ans += V[pcol[p]] * W[donet[pcol[p]]];
122 }
123 void move (int u, int v) {
124     int lca = LCA (u, v);
125     while (u != lca)
126         reverse (u), u = father[u];
127     while (v != lca)
128         reverse (v), v = father[v];
129 }
130 void extime (int p, int type) {
131     bool exist = false;
132     if (state[modposi[p]]) {
133         exist = true;
134         reverse (modposi[p]);
135     }
136     if (type == 1) {
137         modpre[p] = pcol[modposi[p]];
138         pcol[modposi[p]] = modval[p];
139     }
140     else {
141         pcol[modposi[p]] = modpre[p];
142     }
143     if (exist)
144         reverse (modposi[p]);
145 }
146 void timemod (int ptime) {
147     while (cur < mind && modtime[cur + 1] <= ptime)
148         extime (++ cur, 1);
149     while (cur > 0 && modtime[cur] > ptime)
150         extime (cur --, 2);
151 }
152 LL answer[MAXQ]= {0};
153 void Moqueue () {
154     int px = 1, py = 1;
155     for (int i = 1; i <= qind; i ++) {
156         int ind = Query[i].index, time = Query[i].time;
157         int x = Query[i].x, y = Query[i].y;
158         timemod (time);
159         move (px, x), px = x;
160         move (py, y), py = y;
161         int lca = LCA (px, py);
162         reverse (lca);
163         answer[ind] = ans;
164         reverse (lca);
165     }
166 }
167 
168 int getnum () {
169     int num = 0;
170     char ch = getchar ();
171 
172     while (! isdigit (ch))
173         ch = getchar ();
174     while (isdigit (ch))
175         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
176 
177     return num;
178 }
179 
180 int main () {
181     N = getnum (), M = getnum (), Q = getnum ();
182     limit = (int) ceil (pow ((double) N, 2.0 / 3.0));
183     for (int i = 1; i <= M; i ++)
184         V[i] = (LL) getnum ();
185     for (int i = 1; i <= N; i ++)
186         W[i] = (LL) getnum ();
187     for (int i = 1; i < N; i ++) {
188         int u = getnum (), v = getnum ();
189         Insert (u, v), Insert (v, u);
190     }
191     for (int i = 1; i <= N; i ++)
192         pcol[i] = getnum ();
193     DFS_bel (1, 0);
194     while (top > 0)
195         belong[Stack[top --]] = lind;
196     DFS_LCA (1, 0), RMQ ();
197     for (int i = 1; i <= Q; i ++) {
198         int opt = getnum ();
199         if (opt == 0) {
200             int p = getnum (), col = getnum ();
201             modposi[++ mind] = p, modtime[mind] = i, modval[mind] = col;
202         }
203         else if (opt == 1) {
204             int x = getnum (), y = getnum ();
205             qind ++, Query[qind] = (QuerySt (qind, i, x, y));
206         }
207     }
208     sort (Query + 1, Query + qind + 1);
209     Moqueue ();
210     for (int i = 1; i <= qind; i ++)
211         printf ("%lld\n", answer[i]);
212 
213     return 0;
214 }
215 
216 /*
217 4 3 5
218 1 9 2
219 7 6 5 1
220 2 3
221 3 1
222 3 4
223 1 2 3 2
224 1 1 2
225 1 4 2
226 0 2 1
227 1 1 2
228 1 4 2
229 */

 

转载于:https://www.cnblogs.com/Colythme/p/10243551.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值