• BZOJ4817[Sdoi2017]树点涂色


    传送门

    sdoi是真的舒服QAQ

    比较神奇的数据结构上树题233

    我们观察这个题的性质 发现将一条到1的路径染色很像LCT的access操作 我们不妨将相同颜色的点放在一个splay里面 然后access的时候 一条重边变成轻边的时候其实是 子树内ans +1 可以理解成原来它和它上面的节点颜色原本是相同的 然后断开边表示颜色不同了 轻边变成重边 子树内ans -1 原因同理 于是我们首先需要LCT来维持树的结构

    子树内加减->我会dfs序上线段树! 于是我们可以用线段树维护子树内答案 询问3就变成了区间rmq

    我们剩下了询问2 询问2怎么做呢? 路径问题! 树上差分!

    我们发现这个“权值”也是满足树上差分的性质的 我们可以对其维护它到1号点的ans记为f[i]

    于是第二问的答案就是f[x]+f[y]-2*f[lca]+1 (比较神奇 无论lca的颜色是否存在在路径上都是满足这个差分的)

    所以我们最后只需要LCT维护树的形态 然后dfs序上线段树维护f 单点查询&区间查询大小值即可QwQ

    附代码。(我的代码真的好看233)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define inf 20021225
    #define mxn 100010
    #define lson x<<1
    #define rson x<<1|1
    #define fa(x) t[x].fa
    #define ls(x) t[x].son[0]
    #define rs(x) t[x].son[1]
    #define not_root(x) (ls(fa(x))==x||rs(fa(x))==x)
    #define ll long long
    #define lg 18
    using namespace std;
    
    struct node{int son[2],fa;bool rev;}t[mxn];
    struct edge{int to,lt;}e[mxn<<1];
    int in[mxn],cnt,dep[mxn],dfn[mxn],tot;
    int ff[mxn],n,sz[mxn],fa[mxn][lg+1],d[mxn];
    struct Segtree
    {
        int mx[mxn<<2],tag[mxn<<2];
        void pushup(int x){mx[x]=max(mx[lson],mx[rson]);}
        void pushdown(int x)
        {
            if(tag[x])
            {
                mx[lson]+=tag[x];
                tag[lson]+=tag[x];
                mx[rson]+=tag[x];
                tag[rson]+=tag[x];
                tag[x]=0;
            }
        }
        void build(int x,int l,int r)
        {
            if(l==r){mx[x]=ff[d[l]];return;}
            int mid=(l+r)>>1;
            build(lson,l,mid);build(rson,mid+1,r);
            pushup(x);
        }
        void modify(int x,int l,int r,int LL,int RR,int v)
        {
            if(l>=LL&&r<=RR){mx[x]+=v;tag[x]+=v;return;}
            int mid=(l+r)>>1;pushdown(x);
            if(LL<=mid)	modify(lson,l,mid,LL,RR,v);
            if(RR>mid)	modify(rson,mid+1,r,LL,RR,v);
            pushup(x);
        }
        int query(int x,int l,int r,int LL,int RR)
        {
            if(l>=LL&&r<=RR)	return mx[x];
            int mid=(l+r)>>1,ans=0;pushdown(x);
            if(LL<=mid)	ans=max(ans,query(lson,l,mid,LL,RR));
            if(RR>mid)	ans=max(ans,query(rson,mid+1,r,LL,RR));
            return ans;
        }
        int getans(int x)
        {
            return query(1,1,n,dfn[x],dfn[x]);
        }
    }T;
    
    void add(int x,int y)
    {
        e[++cnt].to=y;e[cnt].lt=in[x];in[x]=cnt;
        e[++cnt].to=x;e[cnt].lt=in[y];in[y]=cnt;
    }
    
    void rotate(int x)
    {
        if(!x||!not_root(x))	return;
        int f=fa(x),gf=fa(f);
        int k=rs(f)==x,p=k^1;
        if(not_root(f))	t[gf].son[t[gf].son[1]==f]=x;
        t[x].fa=gf;t[f].fa=x;
        t[f].son[k]=t[x].son[p];
        if(t[x].son[p])	t[t[x].son[p]].fa=f;
        t[x].son[p]=f;
    }
    
    void splay(int x)
    {
        while(not_root(x))
        {
            int f=fa(x),gf=fa(f);
            if(not_root(gf))
                (rs(f)==x)^(rs(gf)==f)?rotate(x):rotate(f);
            rotate(x);
        }
    }
    
    int findroot(int x)
    {
        while(ls(x))	x=ls(x);
        return x;
    }
    
    void access(int x)
    {
        int y=0,w;
        do
        {
            splay(x);
            if(rs(x))	w=findroot(rs(x)),T.modify(1,1,n,dfn[w],dfn[w]+sz[w]-1,1);
            t[x].son[1]=y;
            if(rs(x))	w=findroot(rs(x)),T.modify(1,1,n,dfn[w],dfn[w]+sz[w]-1,-1);
            y=x;x=t[x].fa;
        }while(x);
    }
    
    void dfs(int x)
    {
        ff[x]=dep[x];dfn[x]=++tot;d[tot]=x;sz[x]=1;t[x].fa=fa[x][0];
        for(int i=1;i<=lg;i++)	fa[x][i]=fa[fa[x][i-1]][i-1];
        for(int i=in[x];i;i=e[i].lt)
        {
            int y=e[i].to;
            if(dep[y])	continue;
            dep[y]=dep[x]+1;fa[y][0]=x;
            dfs(y);sz[x]+=sz[y];
        }
    }
    
    int jump(int x,int len)
    {
        for(int i=0;i<=lg;i++)
            if(len&(1<<i))
                x=fa[x][i];
        return x;
    }
    
    int lca(int x,int y)
    {
        if(dep[x]<dep[y])	swap(x,y);
        x=jump(x,dep[x]-dep[y]);
        if(x==y)	return x;
        for(int i=lg;~i;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int query(int x,int y)
    {
        return T.getans(x)+T.getans(y)-2*T.getans(lca(x,y))+1;
    }
    
    void modify(int x){access(x);}
    
    int qmax(int x)
    {
        return T.query(1,1,n,dfn[x],dfn[x]+sz[x]-1);
    }
    
    int main()
    {
        int m,x,y,opt;
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        dep[1]=1;dfs(1);T.build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&opt);
            if(opt==1)
            {
                scanf("%d",&x);
                modify(x);
            }
            if(opt==2)
            {
                scanf("%d%d",&x,&y);
                printf("%d
    ",query(x,y));
            }
            if(opt==3)
            {
                scanf("%d",&x);
                printf("%d
    ",qmax(x));
            }
        }
        return 0;
    }
  • 相关阅读:
    MySQL binlog中 format_desc event格式解析
    位bit和字节Byte
    MySQL利用mysqlbinlog模拟增量恢复
    mysqldump参数 --master-data详解
    开启MySQL二进制日志
    设置花里胡哨的Xshell字体与背景颜色(超全)
    Python操作MySQL数据库
    给定一个由括号([{)]}其中之一或多个组成的字符串判断是否符合左右括号成对标准,不同括号可任意嵌套
    给定一个字符串str,将str中连续两个字符为a的字符替换为b(一个或连续超过多个字符a则不替换)
    不使用局部变量和for循环或其它循环打印出如m=19,n=2結果为2 4 8 16 16 8 4 2形式的串
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/10321943.html
Copyright © 2020-2023  润新知