BZOJ - 2243: [SDOI2011]染色 树链剖分
2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 10456 Solved: 4013
[Submit][Status][Discuss]
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 5
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
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
Sample Output
3
1
2
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
Source
思路:树链剖分+线段树维护颜色,我们要确定每段颜色的时候,需要记录左右儿子。最后查询u->v的时候要注意,不在一条链上,我们需要判断合并时候的颜色是否相同。
大概就是情况,合并的时候左边的右儿子和右边的做儿子。
#include<bits/stdc++.h> #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pb push_back #define P pair<int,int> #define INF 1e18 #define mod 998244353 using namespace std; const int maxn = 100005; int head[maxn],Next[maxn*20],To[maxn*20],pos[maxn],tot,cnt,n; int son[maxn],fa[maxn],size[maxn],top[maxn],id[maxn],deep[maxn]; int lazy[maxn<<2],num[maxn<<2],ls[maxn<<2],rs[maxn<<2],a[maxn]; void add(int u,int v) { Next[++cnt]=head[u]; head[u]=cnt; To[cnt]=v; } void dfs1(int u,int f,int dep) { fa[u]=f; size[u]=1; deep[u]=dep+1; int mx=0; for(int i=head[u]; i!=-1; i=Next[i]) { int v=To[i]; if(v==f) continue; dfs1(v,u,dep+1); size[u]+=size[v]; if(size[v]>mx) mx=size[v],son[u]=v; } size[u]++; } void dfs2(int u,int tp) { id[u]=++tot; pos[tot]=u; top[u]=tp; if(son[u]) dfs2(son[u],tp); for(int i=head[u]; i!=-1; i=Next[i]) { int v=To[i]; if(v!=son[u]&&v!=fa[u]) dfs2(v,v); } } void push_up(int rt) { ls[rt]=ls[rt<<1]; rs[rt]=rs[rt<<1|1]; num[rt]=num[rt<<1]+num[rt<<1|1]-(ls[rt<<1|1]==rs[rt<<1]); } void push_down(int rt) { if(lazy[rt]!=-1) { num[rt<<1]=num[rt<<1|1]=1; lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; ls[rt<<1]=rs[rt<<1]=lazy[rt]; ls[rt<<1|1]=rs[rt<<1|1]=lazy[rt]; lazy[rt]=-1; } } void build(int l,int r,int rt) { lazy[rt]=-1; if(l==r) { ls[rt]=rs[rt]=a[pos[l]]; num[rt]=1; return; } int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } void updata(int l,int r,int rt,int L,int R,ll c) { if(L<=l&&r<=R) { lazy[rt]=ls[rt]=rs[rt]=c; num[rt]=1; return ; } push_down(rt); int m=(l+r)>>1; if(L<=m) updata(lson,L,R,c); if(R>m) updata(rson,L,R,c); push_up(rt); } void change(int u,int v,ll c) { while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); updata(1,n,1,id[top[u]],id[u],c); u=fa[top[u]]; } if(deep[u]>deep[v]) swap(u,v); updata(1,n,1,id[u],id[v],c); } int query(int l,int r,int rt,int L,int R) { if(L<=l&&r<=R) { return num[rt]; } push_down(rt); ll ans=0; int m=(l+r)>>1; if(L<=m) ans+=query(lson,L,R); if(R>m) ans+=query(rson,L,R); if(L<=m&&R>m&&rs[rt<<1]==ls[rt<<1|1]) ans--; return ans; } int Qcolor(int l,int r,int rt,int pos) { if(l==r) return ls[rt]; push_down(rt); int m=(l+r)>>1; if(pos<=m) return Qcolor(lson,pos); else return Qcolor(rson,pos); } int Query(int u,int v) { int ans=0; while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); ans+=query(1,n,1,id[top[u]],id[u])-(Qcolor(1,n,1,id[top[u]])==Qcolor(1,n,1,id[fa[top[u]]])); u=fa[top[u]]; } if(deep[u]>deep[v]) swap(u,v); return ans+query(1,n,1,id[u],id[v]); } int main() { int m,u,v; memset(head,-1,sizeof(head)); scanf("%d %d",&n,&m); for(int i=1; i<=n; i++) scanf("%d",&a[i]); for(int i=1; i<n; i++) { scanf("%d %d",&u,&v); add(u,v); add(v,u); } dfs1(1,-1,0); dfs2(1,1); build(1,n,1); while(m--) { char op[5]; int a,b,c; scanf("%s%d%d",op,&a,&b); if(op[0]=='Q') { printf("%d\n",Query(a,b)); } else { scanf("%d",&c); change(a,b,c); } } }
PS:摸鱼怪的博客分享,欢迎感谢各路大牛的指点~