# [Bzoj2243][SDOI2011]染色(线段树&&树剖||LCT)

  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];
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() {
18     len = 0, dfx = 0;
19 }
20 void add(int s, int e) {//邻接表存值
21     edge[len].s = s;
22     edge[len].e = e;
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);
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);
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编辑  收藏  举报