zoukankan      html  css  js  c++  java
  • 树点涂色

     我们定义f(x),表示x与fa[x]的颜色是否相同,相同为0,不同为1,令 f(1)=1。g(x)表示x到root路径上的f的和。然后考虑怎么维护g(x)。 

     对于操作1,用LCT中的access操作来维护。

    对于操作2,直接线段树查询。

    对于操作3,维护一个最大值,然后区间查询最大值就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 400010
    using namespace std;
    int point[N],nxt[N],v[N],tr[N],delta[N],l[N],r[N],deep[N],mi[20];
    int n,m,k,col[N],f[N][20],fa[N],ch[N][3],tot,sz,pos[N],cur[N];
    void add(int x,int y){
        tot++;nxt[tot]=point[x];point[x]=tot;v[tot]=y;
        tot++;nxt[tot]=point[y];point[y]=tot;v[tot]=x;
    }
    void dfs(int rt){
        int x=rt; 
        while (true) {
            if (!deep[x]) {
                deep[x]=deep[f[x][0]]+1; 
                for (int i=1;i<=17;i++) {
                    if (deep[x]-mi[i]<0) break;
                    f[x][i]=f[f[x][i-1]][i-1];
                }
                l[x]=r[x]=++sz; pos[sz]=x; cur[x]=point[x];
            }
            bool pd=false;
            for (int i=cur[x];i;i=nxt[i]) {
                cur[x]=nxt[i];
                if (v[i]!=f[x][0]) {
                    f[v[i]][0]=fa[v[i]]=x; x=v[i]; pd=true;
                    break;
                }
            }
            if (!pd) {
                int t=f[x][0];// cout<<t<<endl;
                r[t]=max(r[t],r[x]);
                if (x==rt)  break;
                x=t;
            }
        }
    }
    int lca(int x,int  y){
        if (deep[x]<deep[y]) swap(x,y);
        int k=deep[x]-deep[y];
        for (int i=0;i<=17;i++)
         if ((k>>i)&1) x=f[x][i];
        if (x==y) return x;
        for (int i=17;i>=0;i--)
         if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    void update(int now){
        tr[now]=max(tr[now<<1],tr[now<<1|1]);
    }
    void pushdown(int now){
        if (delta[now]) {
            tr[now<<1]+=delta[now]; tr[now<<1|1]+=delta[now];
            delta[now<<1]+=delta[now]; delta[now<<1|1]+=delta[now];
            delta[now]=0;
        }
    }
    void change(int now,int l,int r,int ll,int rr,int val){
        if (ll<=l&&r<=rr) {
            tr[now]+=val; delta[now]+=val;
            return;
        }
        int mid=(l+r)/2; 
        pushdown(now);
        if (ll<=mid) change(now<<1,l,mid,ll,rr,val);
        if (rr>mid) change(now<<1|1,mid+1,r,ll,rr,val);
        update(now);
    }
    int find(int now,int l,int r,int x){
        if (l==r) return tr[now];
        int mid=(l+r)/2;
        pushdown(now);
        if (x<=mid) return find(now<<1,l,mid,x);
        else return find(now<<1|1,mid+1,r,x);
    }
    int query(int now,int l,int r,int ll,int rr){
        if (ll<=l&&r<=rr) return tr[now];
        int mid=(l+r)/2; int ans=0;
        pushdown(now);
        if (ll<=mid) ans=max(ans,query(now<<1,l,mid,ll,rr));
        if (rr>mid) ans=max(ans,query(now<<1|1,mid+1,r,ll,rr));
        return ans;}
    bool isroot(int x){
        return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;
    }
    int get(int x){
        return ch[fa[x]][1]==x;
    }
    void rotate(int x){
        int y=fa[x]; int z=fa[y]; int which=get(x);
        if (!isroot(y)) ch[z][ch[z][1]==y]=x;
        fa[x]=z; fa[y]=x; ch[y][which]=ch[x][which^1];
        fa[ch[x][which^1]]=y; ch[x][which^1]=y;
    }
    void splay(int x){
        int y;
        while (!isroot(x)){
            y=fa[x];
            if (!isroot(y)) rotate(get(y)==get(x)?y:x);
            rotate(x);
        }
    }
    int get_root(int x){
        while (ch[x][0]) x=ch[x][0];
        return x;
    }
    void access(int x){
        int t=0;
        while (x) {
            col[x]=k;
            splay(x);
            int t1=get_root(ch[x][1]);
            if (t1) change(1,1,n,l[t1],r[t1],1);
            ch[x][1]=t;
            int t2=get_root(t);
            if (t2) change(1,1,n,l[t2],r[t2],-1);
            t=x; x=fa[x];
        }
    }
    int main(){
        scanf("%d%d",&n,&m); k=n; mi[0]=1;
        for (int i=1;i<=18;i++) mi[i]=mi[i-1]*2;
        for (int i=1;i<n;i++) {
            int x,y; scanf("%d%d",&x,&y);
            add(x,y);
        }
        dfs(1);
        for (int i=1;i<=n;i++) change(1,1,n,l[i],r[i],1);
        for (int i=1;i<=m;i++) {
            int opt,x,y; scanf("%d%d",&opt,&x);
            if (opt==1) k++,access(x);
            if (opt==2) {
                scanf("%d",&y); int t=lca(x,y);
                printf("%d
    ",find(1,1,n,l[x])+find(1,1,n,l[y])-2*find(1,1,n,l[t])+1);
            }
            if (opt==3) printf("%d
    ",query(1,1,n,l[x],r[x]));
        }
    }
  • 相关阅读:
    [bzoj 1031][JSOI2007]字符加密Cipher
    [bzoj 3224] tyvj 1728 普通平衡树
    分治算法例题
    Codeforces 1146F. Leaf Partition(树形DP)
    Codeforces 1146H. Satanic Panic(极角排序+DP)
    Codeforces 578E. Walking!(贪心+线段树)
    学习日记0802函数递归,三元表达式,列表生成式,字典生成式,匿名函数+内置函数
    学习日记0808
    0803学习日志迭代器
    学习日记0804生成器
  • 原文地址:https://www.cnblogs.com/harden/p/6701749.html
Copyright © 2011-2022 走看看