[Bzoj2243][SDOI2011]染色(线段树&&树剖||LCT)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2243
线段树+树链剖分,在线段树需要每次用lt和rt两个数组记录当前区间的左右边界的颜色,向上更新时需要判断左区间的右边界是否和右区间的左边界相等。在剖分求LCA的过程中需要在求值之后查询与下一次求值的边界是否相等。
1 #include<bits/stdc++.h> 2 #define lson l,mid,i<<1 3 #define rson mid+1,r,i<<1|1 4 using namespace std; 5 typedef long long ll; 6 const int maxn = 200005; 7 const int INF = 2e9; 8 struct node { 9 int s, e, next; 10 }edge[maxn * 2]; 11 int n, m; 12 int son[maxn], top[maxn], tid[maxn], fat[maxn], siz[maxn], dep[maxn], rak[maxn]; 13 int head[maxn], len, dfx; 14 //siz保存以i为根的子树节点个数,top保存i节点所在链的顶端节点,son保存i节点的重儿子,fat保存i节点的父亲节点 15 //dep保存i节点的深度(根为1),,tid保存i节点dfs后的新编号,rak保存新编号i对应的节点(rak[i]=j,tid[j]=i)。 16 void init() { 17 memset(head, -1, sizeof(head)); 18 len = 0, dfx = 0; 19 } 20 void add(int s, int e) {//邻接表存值 21 edge[len].s = s; 22 edge[len].e = e; 23 edge[len].next = head[s]; 24 head[s] = len++; 25 } 26 //搜出每个节点的siz,son,fat,dep 27 void dfs1(int x, int fa, int d) { 28 siz[x] = 1, son[x] = -1, fat[x] = fa, dep[x] = d; 29 for (int i = head[x]; i != -1; i = edge[i].next) { 30 int y = edge[i].e; 31 if (y == fa) 32 continue; 33 dfs1(y, x, d + 1); 34 siz[x] += siz[y]; 35 if (son[x] == -1 || siz[y] > siz[son[x]]) 36 son[x] = y; 37 } 38 } 39 //搜出每个节点的top,tid,rak 40 void dfs2(int x, int c) { 41 top[x] = c; 42 tid[x] = ++dfx; 43 rak[dfx] = x; 44 if (son[x] == -1) 45 return; 46 dfs2(son[x], c); 47 for (int i = head[x]; i != -1; i = edge[i].next) { 48 int y = edge[i].e; 49 if (y == fat[x] || y == son[x]) 50 continue; 51 dfs2(y, y); 52 } 53 } 54 int a[maxn]; 55 int cr[maxn * 2]; 56 int rt[maxn * 2]; 57 int lt[maxn * 2]; 58 int lazy[maxn * 2]; 59 void up(int i) { 60 lt[i] = lt[i << 1], rt[i] = rt[i << 1 | 1]; 61 cr[i] = cr[i << 1] + cr[i << 1 | 1]; 62 if (lt[i << 1 | 1] == rt[i << 1]) 63 cr[i]--; 64 } 65 void down(int i) { 66 if (lazy[i] != -1) { 67 lt[i << 1] = lt[i << 1 | 1] = rt[i << 1] = rt[i << 1 | 1] = lazy[i]; 68 cr[i << 1] = cr[i << 1 | 1] = cr[i]; 69 lazy[i << 1] = lazy[i << 1 | 1] = lazy[i]; 70 lazy[i] = -1; 71 } 72 } 73 void build(int l, int r, int i) { 74 lazy[i] = -1; 75 if (l == r) { 76 cr[i] = 1; 77 rt[i] = a[rak[l]]; 78 lt[i] = a[rak[l]]; 79 return; 80 } 81 int mid = (l + r) >> 1; 82 build(lson); 83 build(rson); 84 up(i); 85 } 86 void update(int L, int R, int k, int l, int r, int i) { 87 if (L <= l && r <= R) { 88 cr[i] = 1; 89 lazy[i] = k; 90 lt[i] = rt[i] = k; 91 return; 92 } 93 down(i); 94 int mid = (l + r) >> 1; 95 if (L <= mid) 96 update(L, R, k, lson); 97 if (R > mid) 98 update(L, R, k, rson); 99 up(i); 100 } 101 int qquery(int L, int R, int l, int r, int i) { 102 if (L <= l && r <= R) return cr[i]; 103 down(i); 104 int mid = (l + r) >> 1; 105 if (R <= mid) return qquery(L, R, lson); 106 if (L > mid) return qquery(L, R, rson); 107 int ans1 = qquery(L, R, lson); 108 int ans2 = qquery(L, R, rson); 109 int ans = ans1 + ans2; 110 if (rt[i << 1] == lt[i << 1 | 1]) ans--; 111 return ans; 112 } 113 114 int dquery(int k, int l, int r, int i) { 115 if (l == r) { 116 return lt[i]; 117 } 118 int mid = (l + r) / 2; 119 down(i); 120 if (k <= mid) 121 return dquery(k, lson); 122 else 123 return dquery(k, rson); 124 } 125 int solve(int x, int y, int w, int flg) { 126 int ans = 0; 127 while (top[x] != top[y]) { 128 if (dep[top[x]] < dep[top[y]]) 129 swap(x, y); 130 if (!flg) 131 update(tid[top[x]], tid[x], w, 1, n, 1); 132 else { 133 ans += qquery(tid[top[x]], tid[x], 1, n, 1); 134 if (dquery(tid[top[x]], 1, n, 1) == dquery(tid[fat[top[x]]], 1, n, 1)) 135 ans--; 136 } 137 x = fat[top[x]]; 138 } 139 if (dep[x] < dep[y]) 140 swap(x, y); 141 if (!flg) 142 update(tid[y], tid[x], w, 1, n, 1); 143 else { 144 ans += qquery(tid[y], tid[x], 1, n, 1); 145 return ans; 146 } 147 } 148 int main() { 149 while (scanf("%d%d", &n, &m) != EOF) { 150 for (int i = 1; i <= n; i++) 151 scanf("%d", &a[i]); 152 init(); 153 int x, y, z; 154 for (int i = 0; i < n - 1; i++) { 155 scanf("%d%d", &x, &y); 156 add(x, y); 157 add(y, x); 158 } 159 dfs1(1, 0, 1); 160 dfs2(1, 1); 161 build(1, n, 1); 162 while (m--) { 163 char s[10]; 164 scanf("%s", s); 165 if (s[0] == 'C') { 166 scanf("%d%d%d", &x, &y, &z); 167 solve(x, y, z, 0); 168 } 169 else { 170 scanf("%d%d", &x, &y); 171 printf("%d\n", solve(x, y, 0, 1)); 172 } 173 } 174 } 175 }
LCT的做法好像更简明,只不过down的时候记得交换lv和rv.
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 120010; 5 ll fa[maxn], ch[maxn][2], siz[maxn], val[maxn], sum[maxn], lv[maxn], rv[maxn], lazy2[maxn], lazy[maxn], st[maxn];//父亲节点,左右儿子节点,当前子数节点个数,当前值,lazy标记,辅助数组。 6 inline bool isroot(int x) {//判断x是否为所在splay的根 7 return ch[fa[x]][0] != x && ch[fa[x]][1] != x; 8 } 9 inline void pushup(int x) { 10 lv[x] = ch[x][0] ? lv[ch[x][0]] : val[x]; 11 rv[x] = ch[x][1] ? rv[ch[x][1]] : val[x]; 12 if (ch[x][0] && ch[x][1])sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + 1 - (rv[ch[x][0]] == val[x]) - (lv[ch[x][1]] == val[x]); 13 else if (ch[x][0])sum[x] = sum[ch[x][0]] + (rv[ch[x][0]] != val[x]); 14 else if (ch[x][1])sum[x] = sum[ch[x][1]] + (lv[ch[x][1]] != val[x]); 15 else sum[x] = 1; 16 siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1; 17 } 18 inline void pushr(int x) { 19 swap(ch[x][0], ch[x][1]); 20 swap(lv[x], rv[x]); 21 lazy[x] ^= 1; 22 } 23 inline void pushC(int x, int c) { 24 val[x] = lv[x] = rv[x] = c, sum[x] = 1; 25 lazy2[x] = c; 26 } 27 inline void pushdown(int x) { 28 if (lazy[x]) { 29 if (ch[x][0])lazy[ch[x][0]] ^= 1; 30 if (ch[x][1])lazy[ch[x][1]] ^= 1; 31 swap(ch[x][0], ch[x][1]); 32 lazy[x] = 0; 33 } 34 if (lazy2[x]) { 35 if (ch[x][0])pushC(ch[x][0], lazy2[x]); 36 if (ch[x][1])pushC(ch[x][1], lazy2[x]); 37 lazy2[x] = 0; 38 } 39 } 40 inline void rotate(int x) { 41 int y = fa[x], z = fa[y]; 42 int k = ch[y][1] == x; 43 if (!isroot(y)) 44 ch[z][ch[z][1] == y] = x; 45 fa[x] = z; ch[y][k] = ch[x][k ^ 1]; fa[ch[x][k ^ 1]] = y; 46 ch[x][k ^ 1] = y; fa[y] = x; 47 pushup(y); 48 pushup(x); 49 } 50 inline void splay(int x) { 51 int f = x, len = 0; 52 st[++len] = f; 53 while (!isroot(f))st[++len] = f = fa[f]; 54 while (len)pushdown(st[len--]); 55 while (!isroot(x)) { 56 int y = fa[x]; 57 int z = fa[y]; 58 if (!isroot(y)) 59 rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y); 60 rotate(x); 61 } 62 pushup(x); 63 } 64 inline void access(int x) {//打通根节点到x的实链 65 for (int y = 0; x; x = fa[y = x]) 66 splay(x), ch[x][1] = y, pushup(x); 67 } 68 inline void makeroot(int x) {//将x变为原树的根 69 access(x); splay(x); pushr(x); 70 } 71 int Findroot(int x) {//找根节点 72 access(x), splay(x); 73 while (ch[x][0]) 74 pushdown(x), x = ch[x][0]; 75 splay(x); 76 return x; 77 } 78 inline void split(int x, int y) {//将x到y路径变为play 79 makeroot(x); access(y); splay(y); 80 } 81 inline void Link(int x, int y) {//合法连边 82 makeroot(x); fa[x] = y; 83 } 84 inline void cut(int x, int y) {//合法断边 85 split(x, y); fa[x] = ch[y][0] = 0; pushup(y); 86 } 87 int main() { 88 int n, q; 89 scanf("%d%d", &n, &q); 90 for (int i = 1; i <= n; i++) 91 scanf("%d", &val[i]), lv[i] = rv[i] = val[i], sum[i] = 1; 92 int x, y, z; 93 for (int i = 1; i < n; i++) { 94 scanf("%d%d", &x, &y); 95 Link(x, y); 96 } 97 while (q--) { 98 char s[3]; 99 scanf("%s", s); 100 if (s[0] == 'Q') { 101 scanf("%d%d", &x, &y); 102 split(x, y); 103 printf("%d\n", sum[y]); 104 } 105 else { 106 scanf("%d%d%d", &x, &y, &z); 107 split(x, y); 108 pushC(y, z); 109 } 110 } 111 }