BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243

树链剖分的点剖分+线段树。漏了一个小地方,调了一下午...... 还是要细心啊!

结构体里lc表示这个区间的最左端的颜色,rc表示这个区间的最右端的颜色,sum表示这个区间的颜色段数目。回溯合并的时候要注意,左孩子的右端颜色要是等于右孩子左端颜色 sum就要-1。

代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 using namespace std;
  5 const int MAXN = 2e5 + 5;
  6 struct data {
  7     int next , to;
  8 }edge[MAXN << 1];
  9 struct segtree {
 10     int l , r , sum , lazy; //sum表示颜色段数量,lazy表示颜色延迟标记
 11     int lc , rc; //lc表示区间的最左端颜色,rc表示最右端颜色
 12 }T[MAXN << 2];
 13 int head[MAXN] , tot;
 14 int son[MAXN] , size[MAXN] , par[MAXN] , dep[MAXN] , cnt;
 15 int top[MAXN] , id[MAXN] , fid[MAXN];
 16 int a[MAXN];
 17 
 18 void init() {
 19     memset(head , -1 , sizeof(head));
 20     tot = cnt = 0;
 21 }
 22 
 23 inline void add(int u , int v) {
 24     edge[tot].next = head[u];
 25     edge[tot].to = v;
 26     head[u] = tot++;
 27 }
 28 
 29 void dfs1(int u , int p , int d) {
 30     dep[u] = d , size[u] = 1 , son[u] = u , par[u] = p;
 31     for(int i = head[u] ; ~i ; i = edge[i].next) {
 32         int v = edge[i].to;
 33         if(v == p)
 34             continue;
 35         dfs1(v , u , d + 1);
 36         if(size[v] >= size[son[u]])
 37             son[u] = v;
 38         size[u] += size[v];
 39     }
 40 }
 41 
 42 void dfs2(int u , int p , int t) {
 43     top[u] = t , id[u] = ++cnt;
 44     fid[cnt] = u;
 45     if(son[u] != u)
 46         dfs2(son[u] , u , t);
 47     for(int i = head[u] ; ~i ; i = edge[i].next) {
 48         int v = edge[i].to;
 49         if(v == p || v == son[u])
 50             continue;
 51         dfs2(v , u , v);
 52     }
 53 }
 54 
 55 void pushdown(int p) {
 56     if(T[p].lazy != -1) {
 57         int ls = p << 1 , rs = (p << 1)|1;
 58         T[ls].rc = T[ls].lc = T[rs].lc = T[rs].rc = T[p].lazy;
 59         T[ls].lazy = T[rs].lazy = T[p].lazy;
 60         T[ls].sum = T[rs].sum = 1; //变成同一个颜色 sum就为1了
 61         T[p].lazy = -1;
 62     }
 63 }
 64 
 65 void pushup(int p) {
 66     T[p].lc = T[p << 1].lc , T[p].rc = T[(p << 1)|1].rc; //这里注意要回溯上来,父节点的左右端颜色要更新
 67     T[p].sum = T[p << 1].sum + T[(p << 1)|1].sum - (T[p << 1].rc == T[(p << 1)|1].lc); //合并操作:要是左孩子的最右端颜色等于右孩子最左端颜色,那就需要-1
 68 }
 69 
 70 void build(int p , int l , int r) {
 71     int mid = (l + r) >> 1;
 72     T[p].r = r , T[p].l = l , T[p].lc = a[fid[l]] , T[p].rc = a[fid[r]] , T[p].lazy = -1;
 73     if(l == r) {
 74         T[p].sum = 1;
 75         return ;
 76     }
 77     build(p << 1 , l , mid);
 78     build((p << 1)|1 , mid + 1 , r);
 79     pushup(p);
 80 }
 81 
 82 void update(int p , int l , int r , int color) {
 83     int mid = (T[p].l + T[p].r) >> 1;
 84     if(T[p].l == l && T[p].r == r) {
 85         T[p].sum = 1 , T[p].lazy = T[p].rc = T[p].lc = color;
 86         return ;
 87     }
 88     pushdown(p);
 89     if(r <= mid) {
 90         update(p << 1 , l , r , color);
 91     }
 92     else if(l > mid) {
 93         update((p << 1)|1 , l , r , color);
 94     }
 95     else {
 96         update(p << 1 , l , mid , color);
 97         update((p << 1)|1 , mid + 1 , r , color);
 98     }
 99     pushup(p);
100 }
101 
102 int query(int p , int l , int r) {
103     int mid = (T[p].l + T[p].r) >> 1;
104     if(T[p].l == l && T[p].r == r) {
105         return T[p].sum;
106     }
107     pushdown(p);
108     if(r <= mid) {
109         return query(p << 1 , l , r);
110     }
111     else if(l > mid) {
112         return query((p << 1)|1 , l , r);
113     }
114     else {
115         return query(p << 1 , l , mid) + query((p << 1)|1 , mid + 1 , r) - (T[p << 1].rc == T[(p << 1)|1].lc);
116     }
117 }
118 
119 int query_pos_color(int p , int pos) {
120     int mid = (T[p].l + T[p].r) >> 1;
121     if(T[p].l == T[p].r && pos == T[p].r) {
122         return T[p].lc;
123     }
124     pushdown(p);
125     if(pos <= mid) {
126         query_pos_color(p << 1 , pos);
127     }
128     else {
129         query_pos_color((p << 1)|1 , pos);
130     }
131 }
132 
133 void find_update(int u , int v , int val) {
134     int fu = top[u] , fv = top[v];
135     while(fu != fv) {
136         if(dep[fu] >= dep[fv]) {
137             update(1 , id[fu] , id[u] , val);
138             u = par[fu];
139             fu = top[u];
140         }
141         else {
142             update(1 , id[fv] , id[v] , val);
143             v = par[fv];
144             fv = top[v];
145         }
146     }
147     if(dep[u] > dep[v])
148         update(1 , id[v] , id[u] , val);
149     else
150         update(1 , id[u] , id[v] , val);
151 }
152 
153 int find_ans(int u , int v) {
154     int fu = top[u] , fv = top[v] , res = 0;
155     while(fu != fv) {
156         if(dep[fu] >= dep[fv]) {
157             res += query(1 , id[fu] , id[u]);
158             if(query_pos_color(1 , id[fu]) == query_pos_color(1 , id[par[fu]])) //要是fu节点和其父节点颜色相同就-1
159                 res--;
160             u = par[fu];
161             fu = top[u];
162         }
163         else {
164             res += query(1 , id[fv] , id[v]); 
165             if(query_pos_color(1 , id[fv]) == query_pos_color(1 , id[par[fv]])) //上同
166                 res--;
167             v = par[fv];
168             fv = top[v];
169         }
170     }
171     if(dep[u] > dep[v]) {
172         res += query(1 , id[v] , id[u]);
173         return res;
174     }
175     else {
176         res += query(1 , id[u] , id[v]);
177         return res;
178     }
179 } 
180 
181 int main()
182 {
183     int n , m , u , v , val;
184     char q[5];
185     while(~scanf("%d %d" , &n , &m)) {
186         init();
187         for(int i = 1 ; i <= n ; ++i)
188             scanf("%d" , a + i);
189         for(int i = 1 ; i < n ; ++i) {
190             scanf("%d %d" , &u , &v);
191             add(u , v);
192             add(v , u);
193         }
194         dfs1(1 , 1 , 0);
195         dfs2(1 , 1 , 1);
196         build(1 , 1 , cnt);
197         while(m--) {
198             scanf("%s" , q);
199             if(q[0] == 'Q') {
200                 scanf("%d %d" , &u , &v);
201                 printf("%d\n" , find_ans(u , v));
202             }
203             else {
204                 scanf("%d %d %d" , &u , &v , &val);
205                 find_update(u , v , val);
206             }
207         }
208     }
209     return 0;
210 }

 

posted @ 2016-05-30 16:48  Recoder  阅读(164)  评论(0编辑  收藏  举报