zoukankan      html  css  js  c++  java
  • BZOJ 3779 重组病毒 ——LCT 线段树

    发现操作一很像一个LCT的access的操作。

    然后答案就是路径上的虚边的数量。

    然后考虑维护每一个点到根节点虚边的数量,

    每次断开一条偏爱路径的时候,子树的值全部+1,

    连接一条偏爱路径的时候,子树的值全部-1。

    然后就用线段树维护DFS序就可以了。

    但是还有一个换根的操作,发现线段树不能换根,所以直接在线段树上分类讨论进行更新就可以了。

    然后makeroot操作就可以换根了。

    #include <map>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    #define ll long long
    #define maxn 200005
      
    int data[200005];
      
    int n,m,dfn[maxn],id[maxn],f[maxn][21],in[maxn],out[maxn];
    int tim[maxn],dep[maxn];
      
    char opt[11];int x;
      
    namespace ST{
        ll sum[maxn<<3],tag[maxn<<3];
        void update(int o)
        {
            sum[o]=sum[o<<1]+sum[o<<1|1];
            return ;
        }
        void pushdown(int o,int l,int r)
        {
            if (tag[o]!=0)
            {
                int mid=l+r>>1;
                sum[o<<1]+=(mid-l+1)*tag[o];
                sum[o<<1|1]+=(r-mid)*tag[o];
                tag[o<<1]+=tag[o];
                tag[o<<1|1]+=tag[o];
                tag[o]=0;
            }
            return ;
        }
        void build(int o,int l,int r)
        {
            if (l==r)
            {
                sum[o]=data[l];
                tag[l]=0;
                return ;
            }
            int mid=l+r>>1;
            build(o<<1,l,mid);
            build(o<<1|1,mid+1,r);
            update(o);
            return ;
        }
        void modify(int o,int l,int r,int L,int R,int f)
        {
            if (L<=l&&r<=R)
            {
                tag[o]+=f;
                sum[o]+=(r-l+1)*f;
                return ;
            }
            pushdown(o,l,r);
            int mid=l+r>>1;
            if (R<=mid) return modify(o<<1,l,mid,L,R,f),update(o);
            else if (L>mid) return modify(o<<1|1,mid+1,r,L,R,f),update(o);
            else return modify(o<<1,l,mid,L,R,f),modify(o<<1|1,mid+1,r,L,R,f),update(o);
        }
        ll querysum(int o,int l,int r,int L,int R)
        {
            if (L<=l&&r<=R) return sum[o];
            pushdown(o,l,r);
            int mid=l+r>>1;
            if (R<=mid) return querysum(o<<1,l,mid,L,R);
            else if (L>mid) return querysum(o<<1|1,mid+1,r,L,R);
            else return querysum(o<<1,l,mid,L,R)+querysum(o<<1|1,mid+1,r,L,R);
        }
        int Second_LCA(int a,int b)
        {
            if (dep[a]>dep[b]) swap(a,b);
            int dist=dep[b]-dep[a]-1; //printf("dist %d
    ",dist);
            D(i,20,0) if ((dist>>i)&1) b=f[b][i];
            return b;
        }
        int LCA(int a,int b)
        {
            if (dep[a]>dep[b]) swap(a,b);
            int dist=dep[b]-dep[a];
            D(i,20,0) if ((dist>>i)&1) b=f[b][i];
            if (a==b) return b;
            D(i,20,0) if (f[b][i]!=f[a][i]) b=f[b][i],a=f[a][i];
            return f[b][0];
        }
        double query(int rt,int o)
        {
            if (o==rt)
            {
                return (1.0*querysum(1,1,n,1,n))/(1.0*n);
            }
            else if (LCA(rt,o)==rt) return (querysum(1,1,n,in[o],out[o]))/(1.0*(out[o]-in[o]+1));
            else if (LCA(rt,o)==o)
            {
                int tmp=Second_LCA(rt,o);
                return (1.0*querysum(1,1,n,1,n)-1.0*querysum(1,1,n,in[tmp],out[tmp]))/(1.0*(n-out[tmp]+in[tmp]-1));
            }
            else
            {
                return (1.0*querysum(1,1,n,in[o],out[o]))/(1.0*(out[o]-in[o]+1));
            }
        }
        void add(int rt,int o,int f)
        {
            if (!o) return ;
            if (o==rt) return modify(1,1,n,1,n,f);
            else if (LCA(rt,o)==rt) return modify(1,1,n,in[o],out[o],f);
            else if (LCA(rt,o)==o)
            {
                int tmp=Second_LCA(rt,o);
                modify(1,1,n,1,n,f);
                modify(1,1,n,in[tmp],out[tmp],-f);
            }
            else return modify(1,1,n,in[o],out[o],f);
        }
    }
      
    namespace LCT{
        int rev[maxn],ch[maxn][2],fa[maxn];
        int sta[maxn],top,rt=1;
        bool isroot(int o)
        {return (ch[fa[o]][0]!=o)&&(ch[fa[o]][1]!=o);}
        void pushdown(int o)
        {
            if (rev[o])
            {
                rev[o]^=1;
                rev[ch[o][0]]^=1;
                rev[ch[o][1]]^=1;
                swap(ch[o][0],ch[o][1]);
            }
        }
        void rot(int x)
        {
            int y=fa[x],z=fa[y],l,r;
            if (ch[y][0]==x) l=0; else l=1; r=l^1;
            if (!isroot(y))
            {
                if (ch[z][0]==y) ch[z][0]=x;
                else ch[z][1]=x;
            }
            fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
            ch[y][l]=ch[x][r]; ch[x][r]=y;
        }
        void splay(int x)
        {
            sta[top=1]=x;
            for (int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i];
            while (top) pushdown(sta[top--]);
              
            while (!isroot(x))
            {
                int y=fa[x];
                if (!isroot(y))
                {
                    int z=fa[y];
                    if (ch[y][0]==x^ch[z][0]==y) rot(x);
                    else rot(y);
                }
                rot(x);
            }
        }
        int find(int x)
        {
            pushdown(x);
            while (ch[x][0]) x=ch[x][0],pushdown(x);
            return x;
        }
        void access(int x)
        {
            for (int t=0;x;t=x,x=fa[x])
            {
                splay(x);
                ST::add(rt,find(ch[x][1]),1);
                ch[x][1]=t;
                ST::add(rt,find(t),-1);
            }
        }
        void makeroot(int x)
        {
            access(x);
            splay(x);
            rev[x]^=1;
            rt=x;
        }
    }
      
    namespace Graph{
        int h[maxn],to[maxn],ne[maxn],en=0,tot=0;
        void add(int a,int b){to[en]=b;ne[en]=h[a];h[a]=en++;}
        void dfs(int o,int fa)
        {
            in[o]=dfn[o]=++tot; id[tot]=o; f[o][0]=fa;
            for (int i=h[o];i>=0;i=ne[i])
                if (to[i]!=fa) dep[to[i]]=dep[o]+1,tim[to[i]]=tim[o]+1,dfs(to[i],o);
            out[o]=tot;
        }
    }
      
    int main()
    {
        memset(Graph::h,-1,sizeof Graph::h);
        scanf("%d%d",&n,&m);
        F(i,1,n-1)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            Graph::add(a,b);Graph::add(b,a);
        }
        tim[1]=1; Graph::dfs(1,0);
        F(i,1,n) LCT::fa[i]=f[i][0];
        F(i,1,20) F(j,1,n) f[j][i]=f[f[j][i-1]][i-1];
        F(i,1,n) data[dfn[i]]=tim[i];
        ST::build(1,1,n);
        F(i,1,m)
        {
            scanf("%s%d",opt,&x);
            switch(opt[2])
            {
                case 'Q': printf("%.10lf
    ",ST::query(LCT::rt,x)); break;
                case 'C': LCT::makeroot(x); break;
                case 'L': LCT::access(x); break;
            }
        }
    }
    

      

  • 相关阅读:
    关于java中面向对象特征的总结
    Jemter TCP压测坑:Hex-encoded binary string contains an uneven no. of digits,Hex-encoded binary string contains an uneven no. of digits
    distinct&group by去重的区别
    Idea从gitee上clone项目时候相关问题
    Nginx正向代理
    docker安装MySQL5.7
    Ubuntu server18.04.5环境配置
    Ubuntu18.04.5 server wifi的连接
    git commit 提交规范
    关于js的学习的推介
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6727062.html
Copyright © 2011-2022 走看看