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;
}
posted @ 2018-06-19 20:18  XSamsara  阅读(127)  评论(0编辑  收藏  举报