zoukankan      html  css  js  c++  java
  • [WC2014]紫荆花之恋(动态点分治+替罪羊思想)

    题目描述
    强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点。每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 i 都有一个感受能力值Ri ,小精灵 i, j 成为朋友当且仅当在树上 i 和 j 的距离 dist(i,j) ≤ Ri + Rj,其中 dist(i, j)表示在这个树上从 i 到 j 的唯一路径上所有边的边权和。强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。  
    我们假定这个树一开始为空,节点按照加入的顺序从 1开始编号。由于强强非常好奇, 你必须在他每次出现新节点后马上给出总共的朋友对数,不能拖延哦。
    题解
    先考虑给定一棵静态的树,这道题怎么做,显然这是经典的点分治分题,假设当前分治中心为u,对于一个点对ij产生贡献时,当且仅当dis[i]+dis[j]<=r[i]+r[j] -> dis[i]-r[i]<=r[j]-dis[j],我们考虑用平衡树维护所有的dis[i]-r[i]然后用r[i]-dis[i]在平衡树中查有多个数小于等于它就可以了。
    那么问题来了,这棵树是动态的,怎么维护。
    考虑暴力,每次新建一个点,连一条边,我们可以把原树想象成一颗点分树,每次从新增节点一直往上跳,边跳边更新,这样的话可以过掉小规模的数据和随机生成的数据。
    因为这样做树高会被卡成O(n)的,所以不能过。
    接下来,我们可以利用替罪羊的思想,每次搞完之后自上而下检查一下,如果发现不平衡,就重构这棵点分树,复杂度同替罪羊树。
    实现细节
    听起来感觉还可做,实现起来*&¥¥%%¥。
    说一下我的具体做法。
    在点分树上的每个节点维护这些信息:该点分树内的所有节点到这个点的距离(平衡树),该点分树内所有点到该点在点分树上的父亲的距离(平衡树),该子树所有点的集合(vector),该点到点分树根的一条链(vector)。
    每次新增的答案就是当前子树的答案-小子树的答案(其实就是减掉不合法的)。
    重构细节很多,注意平衡树的内存回收。
    代码
    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstdlib>
    #define ls tr[p].l
    #define rs tr[p].r
    #define N 100002
    using namespace std;
    typedef long long ll;
    int topp,q[N*32],cnt,head[N],tot,p[N][20],dep[N],size[N],siz[N],dp[N],sum,root,rt[N],n,st[N],top,T[N];
    ll deep[N],dis[N],r[N],ans;
    bool vis[N],tag[N];
    vector<int>vec[N],E[N];
    struct edge{int n,to;ll l;}e[N<<1];
    inline void add(int u,int v,ll l){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l;}
    const double pha=0.75;
    const int mod=1e9;
    struct node{int size,cnt,l,r,rd;ll val;}tr[N*32];
    inline void pushup(int p){tr[p].size=tr[ls].size+tr[rs].size+tr[p].cnt;}
    inline int newnode(ll x){
        int y=topp?q[topp--]:++cnt;
        tr[y].l=tr[y].r=0;tr[y].val=x;tr[y].rd=rand();tr[y].size=tr[y].cnt=1;
        return y;
    }
    inline void re(int x){q[++topp]=x;}
    inline void lturn(int &p){
        int x=tr[p].r;tr[p].r=tr[x].l;tr[x].l=p;
        tr[x].size=tr[p].size;pushup(p);p=x;
    }
    inline void rturn(int &p){
        int x=tr[p].l;tr[p].l=tr[x].r;tr[x].r=p;
        tr[x].size=tr[p].size;pushup(p);p=x;
    }
    inline void ins(int &p,ll x){
        if(!p){p=newnode(x);return;}
        tr[p].size++; 
        if(tr[p].val==x){tr[p].cnt++;return;}
        if(x>tr[p].val){
            ins(rs,x);
            if(tr[p].rd>tr[rs].rd)lturn(p);
        }
        else{
            ins(ls,x);
            if(tr[p].rd>tr[ls].rd)rturn(p);
        }
    } 
    inline ll get_rank(int p,ll x){
        if(!p)return 0;
        if(tr[p].val<=x)return tr[ls].size+tr[p].cnt+get_rank(rs,x);
        return get_rank(ls,x);
    }
    void bl(int p){if(ls)bl(ls);printf("%lld ",tr[p].val);if(rs)bl(rs);}
    inline ll rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} 
        return f?-x:x;
    }
    inline int getlca(int a,int b){
        if(dep[a]<dep[b])swap(a,b);
        for(int i=18;i>=0;--i)if(dep[a]-(1<<i)>=dep[b])a=p[a][i];
        if(a==b)return a;
        for(int i=18;i>=0;--i)if(p[a][i]!=p[b][i])a=p[a][i],b=p[b][i];
        return p[a][0];
    }
    inline ll dist(int a,int b){return dis[a]+dis[b]-2*dis[getlca(a,b)];}
    void getsize(int u,int fa){
        siz[u]=1;
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa&&vis[e[i].to]&&!tag[e[i].to]){
            int v=e[i].to;getsize(v,u);siz[u]+=siz[v]; 
        }
    }
    void getroot(int u,int fa){
        dp[u]=0;siz[u]=1;
        for(int i=head[u];i;i=e[i].n)if(vis[e[i].to]&&e[i].to!=fa&&!tag[e[i].to]){
            int v=e[i].to;getroot(v,u);
            siz[u]+=siz[v];dp[u]=max(dp[u],siz[v]);
        } 
        dp[u]=max(sum-siz[u],dp[u]);
        if(dp[u]<dp[root])root=u;
    }
    void getdeep(int u,int fa,int top,int tt){
        ins(rt[top],deep[u]-r[u]);E[top].push_back(u);
        ins(T[tt],deep[u]-r[u]);vec[u].push_back(top);
        size[top]++;
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa&&vis[e[i].to]&&!tag[e[i].to]){
            int v=e[i].to;deep[v]=deep[u]+e[i].l;
            getdeep(v,u,top,tt);
        }
    }
    void solve(int u){
        tag[u]=1;
        size[u]=1;E[u].push_back(u);
        ins(rt[u],-r[u]);
        for(int i=head[u];i;i=e[i].n)if(vis[e[i].to]&&!tag[e[i].to]){
            int v=e[i].to;
            sum=siz[v];root=n+1;
            getroot(v,u);getsize(root,0);
            deep[v]=e[i].l;getdeep(v,u,u,root);
            solve(root);
        }
    }
    void efs(int p){if(!p)return;if(ls)efs(ls);if(rs)efs(rs);re(p);}
    inline void rebuild(int u){
        int ma=E[u].size();
        for(int i=0;i<ma;++i){
            int v=E[u][i];
            st[++top]=v;vis[v]=1;
        }
        ma=vec[u].size();
        int king=ma?vec[u].back():0;
        for(int i=1;i<=top;++i){
            int x=st[i];size[x]=0;
            E[x].clear();
            while(vec[x].size()&&vec[x].back()!=king)vec[x].pop_back();
            efs(rt[x]);efs(T[x]);rt[x]=T[x]=0;
        }
        root=n+1;sum=top;dp[root]=n+1;
        getroot(u,0);getsize(root,0);int haha=root;
        solve(root);
        if(king){
            for(int i=1;i<=top;++i){
              int x=st[i];
              ll d=dist(x,king);
              ins(T[haha],d-r[x]);
            }
        }
        while(top){
            int x=st[top];
            vis[st[top]]=0;
            tag[st[top]]=0;
            top--;
        }
    }
    inline void check(int u){
        int ma=vec[u].size();
        for(int i=1;i<ma;++i){
            int v=vec[u][i],v1=vec[u][i-1];
            if(size[v1]*pha<size[v]){
                rebuild(v1);
                break;
            }
        }
    }
    inline void work(int u,int fa){
        int ma=vec[fa].size();
        for(int i=0;i<ma;++i)vec[u].push_back(vec[fa][i]);
        vec[u].push_back(fa);    
        ins(rt[u],-r[u]);size[u]=1;E[u].push_back(u);
        ma++;
        for(int i=ma-1;i>=0;--i){
            int v=vec[u][i];ll d=dist(u,v);
            size[v]++;E[v].push_back(u);
            int nex=i==ma-1?u:vec[u][i+1];
            ins(rt[v],d-r[u]);ins(T[nex],d-r[u]);
            ans+=get_rank(rt[v],r[u]-d)-get_rank(T[nex],r[u]-d);
        }
        check(u);
    } 
    int main(){
        srand(3783252);
        n=rd();n=rd();
        ll a=rd(),c=rd();r[1]=rd();
        size[1]=1;ins(rt[1],-r[1]);
        E[1].push_back(1);
        printf("%lld
    ",ans);
        for(int i=2;i<=n;++i){
            a=rd();c=rd();r[i]=rd();
            a=a^(ans%mod);    
            add(i,a,c);add(a,i,c);
            dep[i]=dep[a]+1;dis[i]=dis[a]+c;p[i][0]=a;
            for(int j=1;(1<<j)<=dep[i];++j)p[i][j]=p[p[i][j-1]][j-1];
            work(i,a);
            printf("%lld
    ",ans);
        } 
        return 0;
    }  
     
  • 相关阅读:
    防火墙透明模式
    HP管理工具System Management Homepage安装配置
    kbmmw 中JSON 中使用SQL 查询
    kbmmw 中JSON 操作入门
    第一个kbmmw for Linux 服务器
    kbmmw 5.02发布
    kbmmw 5.01 发布
    使用delphi 10.2 开发linux 上的Daemon
    使用unidac 在linux 上无驱动直接访问MS SQL SERVER
    使用delphi 10.2 开发linux 上的webservice
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10050759.html
Copyright © 2011-2022 走看看