(树链剖分+区间合并)HYSBZ - 2243 染色

Posted tak_fate

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(树链剖分+区间合并)HYSBZ - 2243 染色相关的知识,希望对你有一定的参考价值。

题意:

两个操作:

1、把一条树链上的所有点权值变为w。

2、查询一条树链上有多少个颜色段

 

分析:

一看就是区间合并,做这到题首先需要一定的区间合并基础,

不过这题合并这部分在线段树区间合并中已经算是非常的简单的了。

线段树部分没有难度。

那么难点在于,在往LCA上走的时候,我们如何进行区间合并。

本来我想着, 在向上走的时候顺便进行区间判断并且合并,但是似乎有问题。

其实,可以将两步分开,先算出区间没合并之前的颜色段数,再次进行Top,判断颜色是否相等,相等就减掉。

 

代码:

  1 #include <math.h>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <time.h>
  6 #include <algorithm>
  7 #include <iostream>
  8 #include <map>
  9 #include <queue>
 10 #include <set>
 11 #include <string>
 12 #include <vector>
 13 using namespace std;
 14 
 15 const int maxn = 1000000;
 16 const int inf = 0x3f3f3f3f;
 17 
 18 struct Edge {
 19     int to, next;
 20 } edge[maxn << 1];
 21 
 22 int head[maxn], tot;
 23 int top[maxn];
 24 int fa[maxn];
 25 int deep[maxn];
 26 int num[maxn];
 27 int p[maxn];
 28 int fp[maxn];
 29 int son[maxn];
 30 int pos;
 31 
 32 int val[maxn];
 33 
 34 void init() {
 35     tot = 0;
 36     memset(head, -1, sizeof head);
 37     pos = 0;
 38     memset(son, -1, sizeof son);
 39 }
 40 
 41 void addedge(int u, int v) {
 42     edge[tot].to = v;
 43     edge[tot].next = head[u];
 44     head[u] = tot++;
 45 }
 46 void dfs1(int u, int pre, int d) {
 47     deep[u] = d;
 48     fa[u] = pre;
 49     num[u] = 1;
 50     for (int i = head[u]; i != -1; i = edge[i].next) {
 51         int v = edge[i].to;
 52         if (v != pre) {
 53             dfs1(v, u, d + 1);
 54             num[u] += num[v];
 55             if (son[u] == -1 || num[v] > num[son[u]]) son[u] = v;
 56         }
 57     }
 58 }
 59 
 60 void getpos(int u, int sp) {
 61     top[u] = sp;
 62     p[u] = pos++;
 63     fp[p[u]] = u;
 64     if (son[u] == -1) return;
 65     getpos(son[u], sp);
 66     for (int i = head[u]; i != -1; i = edge[i].next) {
 67         int v = edge[i].to;
 68         if (v != son[u] && v != fa[u]) getpos(v, v);
 69     }
 70 }
 71 
 72 struct Node {
 73     int left, right;
 74     int cnt, lcol, rcol;
 75     int lazy;
 76 } node[maxn << 2];
 77 
 78 void build(int n, int left, int right) {
 79     node[n].left = left;
 80     node[n].right = right;
 81     node[n].cnt = node[n].lcol = node[n].rcol = 0;
 82     node[n].lazy = -1;
 83     if (left == right) return;
 84     int mid = (left + right) >> 1;
 85     build(n << 1, left, mid);
 86     build(n << 1 | 1, mid + 1, right);
 87 }
 88 
 89 void push_up(int n) {
 90     node[n].lcol = node[n << 1].lcol;
 91     node[n].rcol = node[n << 1 | 1].rcol;
 92     node[n].cnt = node[n << 1].cnt + node[n << 1 | 1].cnt;
 93     if (node[n << 1].rcol == node[n << 1 | 1].lcol) node[n].cnt--;
 94 }
 95 
 96 void push_down(int n) {
 97     if (node[n].lazy != -1) {
 98         node[n << 1].cnt = 1;
 99         node[n << 1].lcol = node[n << 1].rcol = node[n].lazy;
100         node[n << 1].lazy = node[n].lazy;
101         node[n << 1 | 1].cnt = 1;
102         node[n << 1 | 1].lcol = node[n << 1 | 1].rcol = node[n].lazy;
103         node[n << 1 | 1].lazy = node[n].lazy;
104         node[n].lazy = -1;
105     }
106 }
107 
108 void update(int n, int left, int right, int val) {
109     if (left <= node[n].left && node[n].right <= right) {
110         node[n].cnt = 1;
111         node[n].lcol = node[n].rcol = val;
112         node[n].lazy = val;
113         return;
114     }
115     push_down(n);
116     int mid = (node[n].left + node[n].right) >> 1;
117     if (mid >= left) update(n << 1, left, right, val);
118     if (mid < right) update(n << 1 | 1, left, right, val);
119     push_up(n);
120 }
121 
122 int query_cnt(int n, int left, int right) {
123     if (left <= node[n].left && node[n].right <= right) {
124         return node[n].cnt;
125     }
126     push_down(n);
127     int mid = (node[n].left + node[n].right) >> 1;
128     if (mid >= right)
129         return query_cnt(n << 1, left, right);
130     else if (mid < left)
131         return query_cnt(n << 1 | 1, left, right);
132     else {
133         int lcnt = query_cnt(n << 1, left, right);
134         int rcnt = query_cnt(n << 1 | 1, left, right);
135         int cnt = lcnt + rcnt;
136         if (node[n << 1].rcol == node[n << 1 | 1].lcol) cnt--;
137         push_up(n);
138         return cnt;
139     }
140 }
141 
142 int query_col(int n, int pos) {
143     if (node[n].left == node[n].right) {
144         return node[n].lcol;
145     }
146     push_down(n);
147     int mid = (node[n].left + node[n].right) >> 1;
148     if (pos <= mid)
149         return query_col(n << 1, pos);
150     else
151         return query_col(n << 1 | 1, pos);
152 }
153 
154 int findCnt(int x, int y) {
155     int u = x, v = y;
156     int tmp = 0;
157     int precol = -1;
158     while (top[x] != top[y]) {
159         if (deep[top[x]] < deep[top[y]]) swap(x, y);
160         tmp += query_cnt(1, p[top[x]], p[x]);
161         x = fa[top[x]];
162     }
163     if (deep[x] > deep[y]) swap(x, y);
164     tmp += query_cnt(1, p[x], p[y]);
165     // if (top[u] == top[v]) return tmp;
166     while (top[u] != top[x]) {
167         int col1 = query_col(1, p[top[u]]);
168         int col2 = query_col(1, p[fa[top[u]]]);
169         if (col1 == col2) tmp--;
170         u = fa[top[u]];
171     }
172     while (top[v] != top[x]) {
173         int col1 = query_col(1, p[top[v]]);
174         int col2 = query_col(1, p[fa[top[v]]]);
175         if (col1 == col2) tmp--;
176         v = fa[top[v]];
177     }
178     return tmp;
179 }
180 
181 void Change(int x, int y, int val) {
182     while (top[x] != top[y]) {
183         if (deep[top[x]] < deep[top[y]]) swap(x, y);
184         update(1, p[top[x]], p[x], val);
185         x = fa[top[x]];
186     }
187     if (deep[x] > deep[y]) swap(x, y);
188     update(1, p[x], p[y], val);
189 }
190 
191 int main() {
192     int t;
193     int n;
194     int q;
195     while (~scanf("%d%d", &n, &q)) {
196         init();
197         for (int i = 1; i <= n; i++) {
198             scanf("%d", &val[i]);
199         }
200         for (int i = 0; i < n - 1; i++) {
201             int u, v;
202             scanf("%d%d", &u, &v);
203             addedge(u, v);
204             addedge(v, u);
205         }
206 
207         dfs1(1, 0, 0);
208         getpos(1, 1);
209         build(1, 0, pos - 1);
210         for (int i = 1; i <= n; i++) {
211             update(1, p[i], p[i], val[i]);
212         }
213         scanf("%d", &q);
214         char op[10];
215         int u, v;
216         while (q--) {
217             scanf("%s%d%d", op, &u, &v);
218             if (op[0] == Q) {
219                 printf("%d\n", findCnt(u, v));
220             } else {
221                 int val;
222                 scanf("%d", &val);
223                 Change(u, v, val);
224             }
225         }
226     }
227     return 0;
228 }

 

以上是关于(树链剖分+区间合并)HYSBZ - 2243 染色的主要内容,如果未能解决你的问题,请参考以下文章

HYSBZ 2243 染色 (线段树+树链剖分)

HYSBZ 2243-染色 (树链剖分)

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

bzoj2243树链剖分+区间合并

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

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