[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 }

 

posted @ 2019-07-09 19:43  祈梦生  阅读(161)  评论(0编辑  收藏  举报