【bzoj2243】[SDOI2011]染色
2017-03-14 14:38
344 查看
题目链接
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
1
2
对于x,y的操作转化为对于x,lca(x, y)和y,lca(x, y)的操作。
线段数在合并时注意如果左子区间的右端颜色和右子区间的左端颜色相同则减一。树链剖分是若当前重链顶和其父亲颜色相同再减一。最后查询的答案是将x,lca(x, y)和y,lca(x, y)的答案相加并直接减一。
Description
给定一棵有n个节点的无根树和m个操作,操作有2类:1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。Sample Input
6 52 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
31
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。题解
直接树剖加线段树,维护区间颜色段数量,最左端颜色,最右端颜色,和覆盖标记。对于x,y的操作转化为对于x,lca(x, y)和y,lca(x, y)的操作。
线段数在合并时注意如果左子区间的右端颜色和右子区间的左端颜色相同则减一。树链剖分是若当前重链顶和其父亲颜色相同再减一。最后查询的答案是将x,lca(x, y)和y,lca(x, y)的答案相加并直接减一。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define lc (o<<1) #define rc (o<<1|1) using namespace std; const int N = 100000 + 10, M = 200000 + 10; int v ; int to[M], nxt[M], hd ; int dep , siz , bl , pos , fa , son , id ; int n, m, tot, sz; struct Seg{ int l, r; }t[M<<1]; int cov[M<<1], l_cl[M<<1], r_cl[M<<1], sum[M<<1]; void insert(int u, int v){ to[++tot] = v; nxt[tot] = hd[u]; hd[u] = tot; to[++tot] = u; nxt[tot] = hd[v]; hd[v] = tot; } inline void in(int &x){ x = 0; int f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } x *= f; } void init(){ in(n); in(m); for(int i = 1; i <= n; i++) in(v[i]); for(int i = 1; i < n; i++){ int x, y; in(x); in(y); insert(x, y); } } void dfs1(int x){ siz[x] = 1; for(int i = hd[x]; i; i = nxt[i]){ if(to[i] == fa[x]) continue; dep[to[i]] = dep[x] + 1; fa[to[i]] = x; dfs1(to[i]); if(siz[to[i]] > siz[son[x]]) son[x] = to[i]; siz[x] += siz[to[i]]; } } void dfs2(int x, int chain){ pos[x] = ++sz; id[sz] = x; bl[x] = chain; if(!son[x]) return; dfs2(son[x], chain); for(int i = hd[x]; i; i = nxt[i]) if(to[i] != fa[x] && to[i] != son[x]) dfs2(to[i], to[i]); } int Lca(int x, int y){ while(bl[x] != bl[y]){ if(pos[bl[x]] < pos[bl[y]]) swap(x, y); x = fa[bl[x]]; } return pos[x] < pos[y] ? x : y; } void pup(int o){ l_cl[o] = l_cl[lc]; r_cl[o] = r_cl[rc]; sum[o] = sum[lc] + sum[rc] - (r_cl[lc] == l_cl[rc]); } void pdw(int o){ if(cov[o] == -1 || t[o].l == t[o].r) return; sum[lc] = sum[rc] = 1; cov[lc] = cov[rc] = cov[o]; l_cl[lc] = r_cl[lc] = l_cl[rc] = r_cl[rc] = cov[o]; cov[o] = -1; } void build(int o, int l, int r){ t[o].l = l; t[o].r = r; sum[o] = 1; cov[o] = -1; if(l == r){ l_cl[o] = r_cl[o] = cov[o] = v[id[l]]; return; } int mid = (l + r) >& 4000 gt; 1; build(lc, l, mid); build(rc, mid+1, r); pup(o); } void change(int o, int x, int y, int c){ pdw(o); int l = t[o].l, r = t[o].r, mid = (l + r) >> 1; if(l == x && r == y) { l_cl[o] = r_cl[o] = cov[o] = c; sum[o] = 1; return; } if(y <= mid) change(lc, x, y, c); else if(x > mid) change(rc, x, y, c); else change(lc, x, mid, c), change(rc, mid+1, y, c); pup(o); } int query(int o, int x, int y){ pdw(o); int l = t[o].l, r = t[o].r, mid = (l + r) >> 1; if(l == x && r == y) return sum[o]; if(y <= mid) return query(lc, x, y); else if(x > mid) return query(rc, x, y); else return query(lc, x, mid) + query(rc, mid+1, y) - (r_cl[lc] == l_cl[rc]); } int getc(int o, int x){ pdw(o); int l = t[o].l, r = t[o].r, mid = (l + r) >> 1; if(l == r) return l_cl[o]; if(x <= mid) return getc(lc, x); else return getc(rc, x); } int solvesum(int x, int f){ int cnt = 0; while(bl[x] != bl[f]){ cnt += query(1, pos[bl[x]], pos[x]) - (getc(1, pos[bl[x]]) == getc(1, pos[fa[bl[x]]])); x = fa[bl[x]]; } cnt += query(1, pos[f], pos[x]); return cnt; } void solvechange(int x, int f, int c){ while(bl[x] != bl[f]){ change(1, pos[bl[x]], pos[x], c); x = fa[bl[x]]; } change(1, pos[f], pos[x], c); } void work(){ build(1, 1, n); char s[20]; int a, b, c; for(int i = 1; i <= m; i++){ scanf("%s", s); if(s[0] == 'C'){ in(a); in(b); in(c); int t = Lca(a, b); solvechange(a, t, c); solvechange(b, t, c); } else{ in(a); in(b); int t = Lca(a, b); printf("%d\n", solvesum(a, t) + solvesum(b, t) - 1); } } } int main(){ init(); dfs1(1); dfs2(1, 1); work(); return 0; }
相关文章推荐
- 【bzoj 2243】【SDOI2011】染色 题解&代码(C++)
- BZOJ2243 [SDOI2011]染色
- bzoj2243[SDOI2011] 染色
- BZOJ.2243.[SDOI2011]染色(树链剖分)
- BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)
- Bzoj-2243 [SDOI2011]染色(动态树/树链剖分)
- BZOJ-2243 [SDOI2011]染色
- BZOJ 2243 [SDOI2011] 染色 (树链剖分)
- 【BZOJ2243】【SDOI2011】染色(树链剖分+线段树)
- 【bzoj2243】[SDOI2011]染色 树链剖分 (区间合并处理)
- BZOJ-2243: [SDOI2011]染色-树链剖分
- [BZOJ2243] [SDOI2011]染色
- 【BZOJ - 2243】 SDOI2011 染色
- bzoj2243[SDOI2011]染色 (树剖)
- BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并
- [BZOJ2243][SDOI2011]染色 解题报告|树链剖分
- bzoj2243 sdoi2011 染色 paint
- bzoj 2243: [SDOI2011]染色
- BZOJ2243: [SDOI2011]染色
- bzoj 2243:[SDOI2011]染色 树链剖分