(树链剖分+区间合并)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 染色的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并