BZOJ 2243: [SDOI2011]染色【树剖+线段树】
【题目描述】
传送门
【题解】
其实就是树剖+线段树,线段树如何判断连续段数量,也就是在Lson和Rson合并时加一句判断,Lson有段和Rson左端是否相同,相同-1,否则不变。
然后LCA时也要记一下,判小心一点,就可以了。
代码如下
#include<cstdio>
#include<algorithm>
#define MAXN 100005
using namespace std;
int n,m,a[MAXN],Wt[MAXN],LT,RT;
int cnt,Fa[MAXN],ID[MAXN],Siz[MAXN],Dep[MAXN],Son[MAXN],Top[MAXN];
int Tre[MAXN<<2],LC[MAXN<<2],RC[MAXN<<2],Add[MAXN<<2];
struct Edge{
int tot,lnk[MAXN],nxt[MAXN<<1],son[MAXN<<1];
void Add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
}E;
void First(int x,int f){
Fa[x]=f;Dep[x]=Dep[f]+1;Siz[x]=1;
for(int j=E.lnk[x],SizeMax=0;j;j=E.nxt[j])
if(E.son[j]!=f){
First(E.son[j],x);Siz[x]+=Siz[E.son[j]];
if(SizeMax<Siz[E.son[j]]) SizeMax=Siz[E.son[j]],Son[x]=E.son[j];
}
}
void Second(int x,int T){
ID[x]=++cnt;Top[x]=T;Wt[cnt]=a[x];
if(!Son[x]) return;Second(Son[x],T);
for(int j=E.lnk[x];j;j=E.nxt[j])
if(!ID[E.son[j]]) Second(E.son[j],E.son[j]);
}
void PushDown(int x){
if(!Add[x]) return;
Tre[x<<1]=1;LC[x<<1]=Add[x];RC[x<<1]=Add[x];
Tre[x<<1|1]=1;LC[x<<1|1]=Add[x];RC[x<<1|1]=Add[x];
Add[x<<1]=Add[x];Add[x<<1|1]=Add[x];Add[x]=0;
}
void PushUp(int x){Tre[x]=Tre[x<<1]+Tre[x<<1|1]-(RC[x<<1]==LC[x<<1|1]),RC[x]=RC[x<<1|1],LC[x]=LC[x<<1];}
void Build(int x,int l,int r){
if(l==r){Tre[x]=1;LC[x]=Wt[l];RC[x]=Wt[l];return;}
int mid=(r+l)>>1;
Build(x<<1,l,mid);Build(x<<1|1,mid+1,r);
PushUp(x);
}
void Updata(int x,int l,int r,int L,int R,int p){
if(L<=l&&r<=R){Tre[x]=1;LC[x]=p;RC[x]=p;Add[x]=p;return;}
PushDown(x);int mid=(r+l)>>1;
if(L<=mid) Updata(x<<1,l,mid,L,R,p);
if(R>mid) Updata(x<<1|1,mid+1,r,L,R,p);
PushUp(x);
}
int Query(int x,int l,int r,int L,int R){
if(L==l) LT=LC[x];if(R==r) RT=RC[x];
if(L<=l&&r<=R) return Tre[x];
PushDown(x);int mid=(r+l)>>1,t=0,Sum=0;
if(L<=mid) Sum+=Query(x<<1,l,mid,L,R),t++;
if(R>mid) Sum+=Query(x<<1|1,mid+1,r,L,R),t++;
return Sum-(t==2?(RC[x<<1]==LC[x<<1|1]):0);
}
void Change(int x,int y,int p){
while(Top[x]!=Top[y]){
if(Dep[Top[x]]<Dep[Top[y]]) swap(x,y);
Updata(1,1,n,ID[Top[x]],ID[x],p);x=Fa[Top[x]];
}
if(Dep[x]<Dep[y]) swap(x,y);
Updata(1,1,n,ID[y],ID[x],p);
}
int Ask(int x,int y){
int Sum=0,lstx=0,lsty=0;
while(Top[x]!=Top[y]){
if(Dep[Top[x]]<Dep[Top[y]]) swap(x,y),swap(lstx,lsty);
Sum+=Query(1,1,n,ID[Top[x]],ID[x]);x=Fa[Top[x]];
Sum-=(RT==lstx);lstx=LT;
}
if(Dep[x]<Dep[y]) swap(x,y),swap(lstx,lsty);
Sum+=Query(1,1,n,ID[y],ID[x]);
Sum-=(RT==lstx)+(LT==lsty);
return Sum;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("prob.in","r",stdin);
freopen("prob.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
E.Add(x,y);E.Add(y,x);
}
First(1,0);Second(1,1);Build(1,1,n);
for(int i=1;i<=m;i++){
int x,y,p;char ch[10];scanf("%s%d%d",ch,&x,&y);
if(ch[0]=='C') scanf("%d",&p),Change(x,y,p);
else printf("%d\n",Ask(x,y));
}
return 0;
}