【SDOI2011】染色

8 篇文章 0 订阅
7 篇文章 0 订阅

Description

 给定一棵有n个节点的无根树和m个操作,操作有2类:
  1、将节点a到节点b路径上所有点都染成颜色c;
  2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
  请你写一个程序依次完成这m个操作。

Solution

第一眼的水题

这种树上的修改与询问,不是一眼的树链剖分吗!
为了练习动态树,强制性打成了lct。

维护方式

首先肯定要维护颜色段的数量,但是如何转移。
因为lct中左子树的深度小于右子树的深度,那么左子树最深的节点和右子树最浅的节点都会与当前的x相邻,那么我们还需要维护最深的节点和最浅的节点的颜色。
然后转移就很显然了。

Code

#include<iostream>
#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=100007;
int i,j,k,l,n,m,ans,x,y,z;
int t[maxn][2],first[maxn*2],next[maxn*2],last[maxn*2],key[maxn];
int zuo[maxn],you[maxn],se[maxn],num,pfa[maxn],f[maxn],deep[maxn],lca,jia[maxn];
int d[maxn];
char s[10];
void update(int x){
    zuo[x]=(t[x][0])?zuo[t[x][0]]:key[x];
    you[x]=(t[x][1])?you[t[x][1]]:key[x];
    se[x]=se[t[x][0]]+se[t[x][1]]+1;
    if(t[x][0]&&you[t[x][0]]==key[x])se[x]--;
    if(t[x][1]&&zuo[t[x][1]]==key[x])se[x]--;
}
void add(int x,int y){
    last[++num]=y,next[num]=first[x],first[x]=num;
    last[++num]=x,next[num]=first[y],first[y]=num;
}
bool son(int x){if(t[f[x]][0]==x)return 0;return 1;}
void rotate(int x){
    int y=f[x],z=son(x);
    t[y][z]=t[x][1-z];
    if(t[x][1-z])f[t[x][1-z]]=y;f[x]=f[y];
    if(f[x])t[f[x]][son(y)]=x;else pfa[x]=pfa[y],pfa[y]=0;
    t[x][1-z]=y;f[y]=x;
    update(y),update(x);
}
void back(int x,int y){
    if(!x)return;
    zuo[x]=you[x]=jia[x]=key[x]=y,se[x]=1;
}
void down(int x){
    if(jia[x]){
        back(t[x][0],jia[x]);back(t[x][1],jia[x]);
        jia[x]=0;
    }
}
void remove(int x){
    do{
        d[++d[0]]=x;
        x=f[x];
    }while(x);
    while(d[0])down(d[d[0]--]);
}
void splay(int x){
    remove(x);
    while(f[x]){
        if(f[f[x]])if(son(f[x])==son(x))rotate(f[x]);else rotate(x);
        rotate(x);
    }
}
void access(int x){
    int y=0;
    while(x){
        splay(x);
        f[t[x][1]]=0;pfa[t[x][1]]=x;
        t[x][1]=y;f[y]=x;
        pfa[y]=0;
        update(x);
        y=x,x=pfa[x];
    }lca=y;
}
void build(int x,int y){
    access(x);splay(x);pfa[x]=y;
}
void bfs(int x){
    int data[maxn],head=0,tail=1,now,i;
    bool bz[maxn];
    memset(data,0,sizeof(data));memset(bz,0,sizeof(bz));
    data[1]=x,bz[x]=1;
    while(head<tail){
        now=data[++head];
        rep(i,now){
            if(last[i]!=now&&(!bz[last[i]])){
                build(last[i],now);
                data[++tail]=last[i];deep[last[i]]=deep[now]+1;
                bz[last[i]]=1;
            }    
        }
    }
}
int main(){
   // freopen("fan.in","r",stdin);
   // freopen("fan.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n)scanf("%d",&key[i]);
    fo(i,1,n-1)scanf("%d%d",&k,&l),add(k,l);
    bfs(1);
    fo(i,1,m){
        scanf("%s%d%d",s,&x,&y);
        if(s[0]=='C'){
            scanf("%d",&z);
            if(x==y){
                splay(x);key[x]=z;continue;
            }
            if(deep[x]<deep[y])swap(x,y);
            access(x);access(y);splay(x);
            key[lca]=z;
            back(x,z);back(t[lca][1],z);
            update(lca);
        }
        else{
            if(x==y){
                printf("1\n");continue;
            }
            if(deep[x]<deep[y])swap(x,y);
            access(x);access(y);splay(x);
            ans=se[x]+se[t[lca][1]]+1;
            if(zuo[x]==key[lca])ans--;
            if(key[lca]==zuo[t[lca][1]])ans--;
            printf("%d\n",ans);
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值