• [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;
    }  
     
  • 相关阅读:
    java final计算
    浅析Java中的final关键字
    easyui
    Java:类与继承
    java中&和&&
    XML
    JSON
    SQL
    selenium
    Metasploit
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10050759.html
Copyright © 2020-2023  润新知