• 洛谷 P3920 [WC2014]紫荆花之恋


    传送门

    想题5分钟,调题20小时(QAQ)

    我做这题的历程:

    这什么破玩意儿


    如果您听说过「替罪羊式重构点分树」的话这题就很好了。

    首先考虑朴素的点分治:

    每次分治统计路径经过分治中心的点对的贡献。

    (dis_i)为点(i)到分治中心的距离,条件即(dis_i+dis_jle r_i+r_j)

    移个项:(dis_i-r_ile r_j-dis_j)

    (r_i-dis_i)插进平衡树里,查询平衡树中大于等于(dis_i-r_i)的数量。

    动态的做法就很明显了,点分树上每个点开个平衡树。还要容斥减掉同一子树的贡献,用(vector)记录每层上用于容斥的平衡树。

    加点直接在点分树上将(i)(a_i)连边,暴力跳点分树在平衡树里查,并把自己的信息插进去。

    注意到每次都会在某个点下方挂一个点,而点分树的树高要维持在(log)级别。

    很像平衡树。旋转是不可能了,利用替罪羊树的思想重构点分树。

    (siz)为点分树上子树大小。当(maxlimits_{iin son(x)}siz_ige siz_x imes alpha)(alpha)为平衡因子,我定的(0.7))就重构点(i)的子树。

    (asuldb):重构多简单,不就点分治一下吗。

    重构我们要干啥((x)为待重构点):

    • 维护点分树上每个点的儿子,(bfs)得到要重构哪些点
    • 清空每个点的平衡树
    • 保留非重构点的容斥平衡树,清空其他的。注意到容斥的(vector)记录的平衡树在点分树上所属的点深度是递增的。一直pop_back并清空平衡树直到末尾元素为(fa(x))即可。
    • 点分治重构点分树

    为了保证单次重构复杂度是(O(siz_xlog siz_x))的,把子树信息提出来排个序直接build(treap)有随机权值不好build(splay)太慢于是选择替罪羊树。

    (其实假了,还有个排序重构是(O(siz_xlog^2 siz_x))的。。。)

    还要带加点查询点对的距离,可以倍增,我用的(LCT)

    复杂度为(O(nlog^2 n))

    注意垃圾回收。

    全是细节的代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <vector>
    #include <set>
    
    #define maxn 100005
    #define inf 0x3f3f3f3f
    
    const double alpha = 0.7;
    const int mod = 1e9;
    
    using namespace std;
    
    inline int read(){
        int x=0,y=0;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return y?-x:x;
    }
    struct edge{
        int pre,to,l;
    }e[maxn<<1];
    struct ScapeGoatTree{
    #define ls(x) son[x][0]
    #define rs(x) son[x][1]
    #define son(x,y) son[x][y]
        int son[maxn*50][2],dat[maxn*50],siz[maxn*50],pool[maxn*50],a[maxn<<1],len,cnt;
        bool isbad(int node){
            return 1.0*max(siz[ls(node)],siz[rs(node)])>=alpha*siz[node];
        }
        void build(int *base,int l,int r,int &node){
            if(l>r){node=0;return;}
            node=pool[cnt--];
            int mid=l+r>>1;
            dat[node]=base[mid];
            build(base,l,mid-1,ls(node));
            build(base,mid+1,r,rs(node));
            siz[node]=siz[ls(node)]+siz[rs(node)]+1;
        }
        void dfs(int node){
            if(!node)return;
            dfs(ls(node));
            a[++len]=dat[node];
            dfs(rs(node));
            pool[++cnt]=node;
        }
        int push(int &node,int d){
            if(!node){
                dat[node=pool[cnt--]]=d,siz[node]=1;
                ls(node)=rs(node)=0;
                return 0;
            }
            ++siz[node];
            int p=push(son(node,dat[node]<d),d);
            if(isbad(node))return node;
            return p;
        }
        void clear(int &node){
            if(!node)return;
            clear(ls(node)),clear(rs(node));
            pool[++cnt]=node,node=0;
        }
        void insert(int &node,int d){
            int p=push(node,d);
            if(p)len=0,dfs(p),build(a,1,len,p);
        }
        int find(int node,int x){
            int ans=0;
            while(node){
                if(dat[node]>=x)ans+=siz[rs(node)]+1,node=ls(node);
                else node=rs(node);
            }
            return ans;
        }
        ScapeGoatTree(){
            cnt=maxn*50-1;
            for(register int i=1;i<=cnt;++i)pool[i]=i;
        }
    }sgt;
    struct LinkCutTree{
    #define whson(x) (son(fa[x],1)==x)
    #define isroot(x) (son(fa[x],0)!=x&&son(fa[x],1)!=x)
        int son[maxn<<1][2],fa[maxn<<1],sum[maxn<<1],v[maxn<<1],rev[maxn<<1],sta[maxn<<1];
        inline void update(int node){
            sum[node]=sum[ls(node)]+sum[rs(node)]+v[node];
        }
        inline void addedge(int s,int f,int wh){
            if(s)fa[s]=f;
            son(f,wh)=s;
        }
        inline void reverdown(int node){
            swap(ls(node),rs(node)),rev[node]^=1;
        }
        inline void pushdown(int node){
            if(rev[node])reverdown(ls(node)),reverdown(rs(node)),rev[node]=0;
        }
        void zhuan(int x){
            int f=fa[x],gf=fa[f],wh=whson(x);
            fa[x]=gf;
            if(!isroot(f))son(gf,whson(f))=x;
            addedge(son(x,wh^1),f,wh);
            addedge(f,x,wh^1);
            update(f),update(x);
        }
        void splay(int x){
            int y=x,top=1;
            sta[1]=x;
            while(!isroot(y))sta[++top]=y=fa[y];
            while(top)pushdown(sta[top--]);
            while(!isroot(x)){
                y=fa[x];
                if(!isroot(y))zhuan(whson(y)^whson(x)?x:y);
                zhuan(x);
            }
        }
        void access(int x){
            for(register int y=0;x;y=x,x=fa[x])
                splay(x),son(x,1)=y,update(x);
        }
        void makeroot(int x){
            access(x),splay(x),reverdown(x);
        }
        void link(int x,int y){fa[x]=y;}
        int Get(int x,int y){
            makeroot(x),access(y),splay(y);
            return sum[y];
        }
    }lct;
    int r1[maxn],r2[maxn],h[maxn],siz[maxn],ts[maxn],pool[maxn<<2],num,cnt=(maxn<<2)-1,all,mx,root,l1,l2;
    int mp[maxn],rt[maxn],exc[maxn<<3],line[maxn],dep[maxn],fa[maxn],a[maxn];
    bool vis[maxn],rub[maxn<<1];
    vector<int>b[maxn];
    set<int>son[maxn];
    inline void add(int from,int to,int l){
        e[++num].pre=h[from],h[from]=num,e[num].to=to,e[num].l=l;
    }
    void getroot(int node,int f=0){
        int ma=0,x;
        siz[node]=1;
        for(register int i=h[node];i;i=e[i].pre){
            x=e[i].to;
            if(x==f||vis[x])continue;
            getroot(x,node),ma=max(ma,siz[x]),siz[node]+=siz[x];
        }
        ma=max(ma,all-siz[node]);
        if(ma<mx)mx=ma,root=node;
    }
    void bfs(int node){
        int head=0,tail=1,rc=cnt;
        dep[line[1]=node]=0;
        while(head<tail){
            int x=line[++head];
            vis[x]=0;
            for(set<int>::iterator iter=son[x].begin();iter!=son[x].end();++iter)
                dep[line[++tail]=*iter]=dep[x]+1;
            while(dep[x]--){
                sgt.clear(exc[*b[x].rbegin()]);
                if(!rub[*b[x].rbegin()])rub[pool[++cnt]=*b[x].rbegin()]=1;
                b[x].pop_back();
            }
            sgt.clear(rt[x]);
            son[x].clear();
        }
        for(register int i=rc+1;i<=cnt;++i)rub[pool[i]]=0;
    }
    void dfs(int node,int len,int f){
        r1[++l1]=r2[++l2]=a[node]-len,b[node].push_back(pool[cnt]);
        siz[node]=1;
        int x;
        for(register int i=h[node];i;i=e[i].pre){
            x=e[i].to;
            if(x==f||vis[x])continue;
            dfs(x,len+e[i].l,node),siz[node]+=siz[x];
        }
    }
    void build(int node){
        vis[node]=ts[node]=1,mp[node]=0,r1[l1=1]=a[node];
        int x;
        for(register int i=h[node];i;i=e[i].pre){
            x=e[i].to;
            if(vis[x])continue;
            l2=0,dfs(x,e[i].l,node);
            sort(r2+1,r2+1+l2);
            sgt.build(r2,1,l2,exc[pool[cnt--]]);
        }
        sort(r1+1,r1+1+l1);
        sgt.build(r1,1,l1,rt[node]);
        for(register int i=h[node];i;i=e[i].pre){
            x=e[i].to;
            if(vis[x])continue;
            mx=inf,mp[node]=max(all=siz[x],mp[node]),getroot(x);
            ts[node]+=all,fa[root]=node,son[node].insert(root);
            build(root);
        }
    }
    void rebuild(int node){
        int x=node,p=0;
        while(x){
            mp[fa[x]]=max(mp[fa[x]],++ts[x]);
            if(1.0*mp[x]>=alpha*ts[x])p=x;
            x=fa[x];
        }
        if(p){
            bfs(p);
            mx=inf,all=ts[p],getroot(p);
            fa[root]=fa[p],son[fa[p]].erase(p),son[fa[p]].insert(root);
            build(root);
        }
    }
    int main(){
        memset(vis,1,sizeof vis);
        for(register int i=1;i<=cnt;++i)pool[i]=i;
        read();
        int n=read(),x,y,node;
        long long ans=0;
        read(),read();
        ts[1]=1,sgt.insert(rt[1],a[1]=read()),puts("0");
        for(register int i=2;i<=n;++i){
            x=read<long long>()^(ans%mod),lct.v[n+i]=y=read(),a[i]=read();
            fa[i]=node=x,son[x].insert(i),sgt.insert(rt[i],a[i]);
            add(i,x,y),add(x,i,y),lct.link(n+i,x),lct.link(i,n+i);
            b[i]=b[x],b[i].push_back(pool[cnt--]);
            for(register int j=b[i].size()-1;node;node=fa[node],--j){
                int dis=lct.Get(i,node);
                ans+=sgt.find(rt[node],dis-a[i])-sgt.find(exc[b[i][j]],dis-a[i]);
                sgt.insert(rt[node],a[i]-dis),sgt.insert(exc[b[i][j]],a[i]-dis);
            }
            printf("%lld
    ",ans);
            rebuild(i);
        }
    }
    
  • 相关阅读:
    KVM镜像管理利器-guestfish使用详解
    两台linux机器时间同步
    git配合tortoiseGit的基础使用
    使用yum来下载RPM包而不进行安装
    Linux解压缩总结
    Linux下使用git命令及github项目
    linux shell常用快捷键
    调用 sphinx-build生成HTML文件
    复制virtualenv环境到其他服务器环境配置的方法
    CentOS 6.5 PYPI本地源制作
  • 原文地址:https://www.cnblogs.com/ctz45562/p/11635359.html
Copyright © 2020-2023  润新知