zoukankan      html  css  js  c++  java
  • bzoj千题计划274:bzoj3779: 重组病毒

    http://www.lydsy.com/JudgeOnline/problem.php?id=3779

    有一棵树,初始每个节点有不同的颜色

    操作1:根节点到x的路径上的点 染上一种没有出现过的颜色

    操作2:操作1后把x换成根

    操作3:定义点x的点权为x到根节点路径上不同颜色的数量,查询x的子树点权和

     

    LCT+线段树+dfs序

    dfs一遍得到每个点的dfs序,

    以及每个点子树的dfs序范围,记点x的子树dfs序范围为 [Lx,Rx]

    线段树以dfs序为顺序维护

    操作1就是access,

    一条Preferred Path 上所有点的颜色相同

    在轻重链交换的时候才会涉及到点权的修改

    如果lct上父节点x和子节点y之间的边由重链变轻链,那么lct上 以子节点y为根的子树的所有点 的点权减1

    实现就是找到t的Auxiliary Tree 上深度最小的点z, 区间[Lz,Rz] 减1

    如果lct上父节点x和子节点y之间的边由轻链变重链,那么lct上 以子节点y为根的子树的所有点 的点权加1

    实现就是找到t的Auxiliary Tree 上深度最小的点z, 区间[Lz,Rz] 加1

    操作2就是LCT的换根操作

    不用刻意的去维护换根对线段树的影响,因为换根之前会执行操作1,access

    点到新的根节点路径上的颜色数量 就等于 点到原来根节点路径上的颜色数量

    查询操作:

    分析点x和根节点root 子树的包含关系

    若x==root,那就是查询整棵树

    若x在root的子树内,直接查x的子树

    若root在x的子树内,设root在x的子节点p的子树内,那就是查询整棵树除去p的子树的部分

    查询子树就是 线段树按dfs序维护的一段连续的区间

     

    #include<cmath>
    #include<cstdio>
    #include<iostream>
    
    #define N 100001
    
    using namespace std;
    
    typedef long long LL;
    
    int n;
    int front[N],to[N<<1],nxt[N<<1],tot;
    
    int id[N],dy[N],lst[N],tim;
    int dep[N];
    int lim,F[N][18];
    
    int fa[N],ch[N][2],root;
    bool rev[N];
    
    LL sum[N<<2];
    int siz[N<<2],tag[N<<2];
    
    int st[N],top;
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
    }
    
    void dfs(int x)
    {
        id[x]=++tim;
        dy[tim]=x;
        for(int i=front[x];i;i=nxt[i])
            if(to[i]!=fa[x])
            {
                dep[to[i]]=dep[x]+1;
                F[to[i]][0]=x;
                fa[to[i]]=x;
                dfs(to[i]);
            }
        lst[x]=tim;
    }
    
    void build(int k,int l,int r)
    {
        siz[k]=r-l+1;
        if(l==r)
        {
            sum[k]=dep[dy[l]];
            return;
        }
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    
    void tagging(int k,int w)
    {
        sum[k]+=w*siz[k];
        tag[k]+=w;
    }
    
    void push_down(int k)
    {
        tagging(k<<1,tag[k]);
        tagging(k<<1|1,tag[k]);
        tag[k]=0;
    }
    
    void change(int k,int l,int r,int opl,int opr,int w)
    {
        if(l>=opl && r<=opr)
        {
            tagging(k,w);
            return;
        }
        if(tag[k]) push_down(k);
        int mid=l+r>>1;
        if(opl<=mid) change(k<<1,l,mid,opl,opr,w);
        if(opr>mid) change(k<<1|1,mid+1,r,opl,opr,w);
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    
    void Change(int x,int w)
    {
        if(x==root) change(1,1,n,1,n,w);
        else if(id[root]>id[x] && id[root]<=lst[x])    
        {
            int t=root,c=dep[root]-dep[x]-1;
            for(int i=lim;i>=0;--i)
                if(c&(1<<i)) t=F[t][i];
            if(id[t]>1) change(1,1,n,1,id[t]-1,w);
            if(lst[t]<n) change(1,1,n,lst[t]+1,n,w);
        }
        else change(1,1,n,id[x],lst[x],w);
    }
    
    LL query(int k,int l,int r,int opl,int opr)
    {
        if(l==opl && r==opr) return sum[k];
        if(tag[k]) push_down(k);
        int mid=l+r>>1; LL res=0;
        if(opl<=mid) res+=query(k<<1,l,mid,opl,min(mid,opr));
        if(opr>mid) res+=query(k<<1|1,mid+1,r,max(mid+1,opl),opr);
        return res;
    }
    
    double Query(int x)
    {
        if(x==root) return 1.0*query(1,1,n,1,n)/n;
        else if(id[root]>id[x] && id[root]<=lst[x])
        {
            int t=root,c=dep[root]-dep[x]-1;
            for(int i=lim;i>=0;--i)
                if(c&(1<<i)) t=F[t][i];
            int siz=id[t]-1+n-lst[t];
            LL res=0;
            if(id[t]>1) res+=query(1,1,n,1,id[t]-1);
            if(lst[t]<n) res+=query(1,1,n,lst[t]+1,n);
            return 1.0*res/siz;
        }
        return 1.0*query(1,1,n,id[x],lst[x])/(lst[x]-id[x]+1);
    }
    
    void down(int x)
    {
        rev[x]^=1;
        if(ch[x][0]) rev[ch[x][0]]^=1;
        if(ch[x][1]) rev[ch[x][1]]^=1;
        std::swap(ch[x][0],ch[x][1]);
    }
    
    bool isroot(int x)
    {
        return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
    }
    
    bool getson(int x)
    {
        return ch[fa[x]][1]==x;
    }
    
    void rotate(int x)
    {
        int y=fa[x],z=fa[y];
        bool k=ch[y][1]==x;
        if(!isroot(y)) ch[z][ch[z][1]==y]=x;
        ch[y][k]=ch[x][k^1]; ch[x][k^1]=y;
        fa[y]=x; fa[x]=z; fa[ch[y][k]]=y;
    }
    
    void splay(int x)
    {
        st[top=1]=x;
        for(int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];
        for(int i=top;i;--i) 
            if(rev[st[i]]) down(st[i]);
        int y;
        while(!isroot(x))
        {
            y=fa[x];
            if(!isroot(y)) rotate(getson(x)==getson(y) ? y : x);
            rotate(x);
        }
    }
    
    int find_root(int x)
    {
        if(rev[x]) down(x);
        while(ch[x][0])
        {
            x=ch[x][0];
            if(rev[x]) down(x);
        }
        return x;
    }
    
    void access(int x)
    {
        int t=0;
        while(x)
        {
            splay(x);
            if(ch[x][1]) Change(find_root(ch[x][1]),1);
            ch[x][1]=t;
            if(t) Change(find_root(t),-1);
            t=x; x=fa[x];
        }
    }
    
    void maker_root(int x)
    {
        access(x);
        splay(x);
        rev[x]^=1;
        root=x;
    }
    
    int main()
    {
        freopen("recompile.in", "r", stdin);
        freopen("recompile.out", "w", stdout);
        int m;
        read(n); read(m);
        int u,v;
        for(int i=1;i<n;++i)
        {
            read(u); read(v);
            add(u,v);
        }
        dep[1]=1;
        dfs(1);
        lim=log(n)/log(2);
        for(int j=1;j<=lim;++j)
            for(int i=1;i<=n;++i)
                F[i][j]=F[F[i][j-1]][j-1];
        build(1,1,n);
        root=1;
        char c[3]; int x;
        while(m--)
        {
            scanf("%s",c);
            read(x);
            if(c[2]=='L') access(x);
            else if(c[2]=='C')     maker_root(x);
            else printf("%.10lf
    ",Query(x));
        }
    }
  • 相关阅读:
    NX 8.5 License Server Firewall Setting
    Cisco ASA intra-interface routing
    How to configure windows machine to allow file sharing with dns alias (CNAME)
    Install unifi controller on CentOS
    Android图片加载框架Glide用法
    判断app是否已启动
    SharedPreferences的一个工具类适合的数据类型包括String、Integer、Boolean、Float、Long
    android获取缓存大小和清除缓存
    对字符串进行MD5加密工具类
    android代码设置RelativeLayout的高度
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8550681.html
Copyright © 2011-2022 走看看