BZOJ2243: [SDOI2011]染色
2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 8402 Solved: 3151
[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]之间。
思路{
颜色段发现用树链剖分的时候记录一下区间左右端点,比较一下就可以了.
有点码.....
}
#include<bits/stdc++.h> #define il inline #define RG register #define ll long long #define db double #define N 100010 using namespace std; int w[N]; struct ed{int nxt,to;}e[N*2]; int head[N],tot,n,m; void LINK(int u,int v){e[tot].nxt=head[u];e[tot].to=v;head[u]=tot++;} void link(int u,int v){LINK(u,v),LINK(v,u);} namespace Tree{ #define ls (o<<1) #define rs ((o<<1)|1) #define mid ((l+r)>>1) int id[N],top[N],deep[N],idw[N],fa[N],sz[N],hson[N],idn; int Sum[N*4],lc[N*4],rc[N*4],lazy[N*4]; void dfs1(int u,int faa){ deep[u]=deep[faa]+1;fa[u]=faa;sz[u]=1; for(int i=head[u];i!=-1;i=e[i].nxt)if(e[i].to!=faa){ int v=e[i].to;dfs1(v,u); sz[u]+=sz[v];if(sz[v]>sz[hson[u]])hson[u]=v; } } void dfs2(int u,int toop){ id[u]=++idn;idw[idn]=w[u];top[u]=toop; if(hson[u])dfs2(hson[u],toop); for(int i=head[u];i!=-1;i=e[i].nxt) if(e[i].to!=hson[u]&&e[i].to!=fa[u]) dfs2(e[i].to,e[i].to); } void up(int o){ Sum[o]=Sum[ls]+Sum[rs]; if(rc[ls]==lc[rs])Sum[o]--; rc[o]=rc[rs],lc[o]=lc[ls]; } void build(int o,int l,int r){ if(l==r){Sum[o]=1,rc[o]=lc[o]=idw[l];return;} build(rs,mid+1,r),build(ls,l,mid); up(o); } void down(int o){ if(lazy[o]){ Sum[rs]=Sum[ls]=1; rc[rs]=lc[rs]=lazy[rs]=lazy[o]; rc[ls]=lc[ls]=lazy[ls]=lazy[o]; lazy[o]=0; } } void Modify(int o,int l,int r,int L,int R,int c){ if(l!=r)down(o); if(l>=L&&r<=R){ Sum[o]=1; rc[o]=lc[o]=lazy[o]=c; return; } if(mid<L)Modify(rs,mid+1,r,L,R,c); else if(mid>=R)Modify(ls,l,mid,L,R,c); else Modify(rs,mid+1,r,mid,R,c),Modify(ls,l,mid,L,mid,c); up(o); } int Query(int o,int l,int r,int L,int R){ if(l!=r)down(o); if(l>=L&&r<=R)return Sum[o]; if(mid<L)return Query(rs,mid+1,r,L,R); if(mid>=R)return Query(ls,l,mid,L,R); else return Query(rs,mid+1,r,L,R)+Query(ls,l,mid,L,R)-(rc[ls]==lc[rs]); } int Querycol(int o,int l,int r,int pos){ if(l!=r)down(o);if(l==r)return rc[o]; if(mid<pos)return Querycol(rs,mid+1,r,pos); else return Querycol(ls,l,mid,pos); } void work1(int x,int y,int c){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]])swap(x,y); Modify(1,1,n,id[top[x]],id[x],c); x=fa[top[x]]; } if(deep[x]>deep[y])swap(x,y); Modify(1,1,n,id[x],id[y],c); } void work2(int x,int y){ ll sum(0); while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]])swap(x,y); sum+=Query(1,1,n,id[top[x]],id[x]); if(Querycol(1,1,n,id[top[x]])==Querycol(1,1,n,id[fa[top[x]]]))sum--; x=fa[top[x]]; } if(deep[x]>deep[y])swap(x,y); sum+=Query(1,1,n,id[x],id[y]); cout<<sum<<"\n"; } } char C[2]; int main(){ memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d",&w[i]); for(int i=1;i<n;++i){int u,v;scanf("%d%d",&u,&v),link(u,v);} Tree::dfs1(1,1),Tree::dfs2(1,1);Tree::build(1,1,n); for(int i=1;i<=m;++i){ scanf("%s",C); if(C[0]=='C'){ int a,b,c;scanf("%d%d%d",&a,&b,&c); Tree::work1(a,b,c); } else { int a,b;scanf("%d%d",&a,&b); Tree::work2(a,b); } } return 0; }