动态点分治总结

动态点分治总结

下面是伟大の分割线!

上面是伟大の分割线!

废话

再开一坑。

刷几道题来填。

才刷两题,慢慢补吧。。。。

(这玩意是真的神,调死你

警告:这篇文章中的代码都很丑陋!

下面是伟大の分割线!

上面是伟大の分割线!

思想

前置技能:点分治。

动态点分治就是带修改的点分治。

如果每次单点修改之后重新点分治一遍,被影响到的节点最多\(\log_2n\)个。

然后就有了动态点分治。。。。

点分树

我也不知道这个叫什么反正就是一颗新树。。。

构建方法大概就是点分治solve的时候顺便搞出,它就是solve时的搜索树(?)

可以证明那玩意深度是严格\(\log_2n\)的。

如果修改一个点,只需在对应点分树上修改(暴跳父亲,慢慢修改)

查询也可以暴跳父亲,但有些题不用

下面是伟大の分割线!

上面是伟大の分割线!

例题

cogs2036 捉迷藏

查询最长链。

要维护三种堆= =不看题解写不出= = = = = = = = =

(其实应该是multiset= =但是能用堆来模拟)

首先每个点维护一个堆1,是子树到这个点的距离。(“子树”是点分树,“距离”是原树上的距离)

再维护一个堆2,是所有子树的堆1堆顶

再全局维护一个堆3,是所有点堆2的最大和次大(这里要讨论一下,如果这个点是黑色的,少了的元素用0补上;如果是白色的堆又没有两个元素,就是0)

真•奇丑无比

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
using namespace std;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=100001; 
#define queue priority_queue
struct Queue{
    queue<int>que,del;
    il int siz(){return que.size()-del.size();}
    il int top(){
        if(siz()<1)return 0;
        while(!del.empty()&&que.top()==del.top())que.pop(),del.pop();
        return que.top();
    }
    il vd pop(int x){del.push(x);}
    il vd push(int x){que.push(x);}
};
int n,q,fir[maxn],dis[maxn<<1],nxt[maxn<<1],col[maxn],dep[maxn],id;
il vd link(int x,int y){nxt[++id]=fir[x],fir[x]=id,dis[id]=y;}
Queue que[maxn],Que[maxn],QUE;
int siz[maxn],f[maxn],rt,vis[maxn],sum,FAQ[maxn];
il vd getrt(int x,int FA){
    f[x]=0;siz[x]=1;
    for(int i=fir[x];i;i=nxt[i]){
        if(vis[dis[i]]||FA==dis[i])continue;
        getrt(dis[i],x);
        siz[x]+=siz[dis[i]];
        f[x]=max(f[x],siz[dis[i]]);
    }
    f[x]=max(f[x],sum-siz[x]);
    if(f[x]<f[rt])rt=x;
}
il vd Getrt(int x,int _sum){sum=_sum,rt=0,f[0]=2e9,getrt(x,-1);}
vector<int>S[maxn];int Root;
il vd solve(int x){
    vis[x]=1;
    for(int i=fir[x];i;i=nxt[i]){
        if(vis[dis[i]])continue;
        Getrt(dis[i],siz[dis[i]]);
        FAQ[rt]=x;S[x].push_back(rt);
        solve(rt);
    }
}
int st[17][maxn];
il vd Getdep(int x,int FA=-1){
    for(int i=fir[x];i;i=nxt[i]){
        if(FA==dis[i])continue;
        dep[dis[i]]=dep[x]+1;
        st[0][dis[i]]=x;
        Getdep(dis[i],x);
    }
}
il int dist(int x,int y){
    int ret=dep[x]+dep[y],cha=dep[x]-dep[y];
    if(dep[x]<dep[y])cha=-cha,swap(x,y);
    for(int i=16;~i;--i)if(cha&(1<<i))x=st[i][x];
    for(int i=16;~i;--i)if(st[i][x]^st[i][y])x=st[i][x],y=st[i][y];
    if(x^y)x=st[0][x];
    return ret-2*dep[x];
}
il vd calc(int x,int FA,int Rt){
    que[Rt].push(dist(x,FAQ[Rt]));
    for(vector<int>::iterator i=S[x].begin();i!=S[x].end();++i){
        if(FA==*i)continue;
        calc(*i,x,Rt);
    }
}
il int Top(int x){
    sta int a,b,ret;
    a=Que[x].top();Que[x].pop(a);
    b=Que[x].top();Que[x].push(a);
    if(col[x])ret=a+b;
    else if(a&&b)ret=a+b;
    else ret=0;
    return ret;
}
il vd Solve(int x){
    calc(x,-1,x);
    for(vector<int>::iterator i=S[x].begin();i!=S[x].end();++i){
        Solve(*i);
        Que[x].push(que[*i].top());
    }
    QUE.push(Top(x));
}
int main(){
    freopen("hide.in","r",stdin);
    freopen("hide.out","w",stdout);
    n=gi();int x,y,tot=n;
    for(rg int i=1;i<=n;++i)col[i]=1;
    for(rg int i=1;i<n;++i)x=gi(),y=gi(),link(x,y),link(y,x);
    Getrt(1,n),Root=rt,solve(rt);
    dep[1]=0,Getdep(1);
    for(rg int i=1;i<17;++i)
        for(rg int j=1;j<=n;++j)
            st[i][j]=st[i-1][st[i-1][j]];
    Solve(Root);
    q=gi();char opt[5];
    while(q--){
        scanf("%s",opt);
        if(opt[0]=='G'){
            if(tot<2)printf("%d\n",tot-1);
            else printf("%d\n",QUE.top());
        }
        else{
            x=gi();y=1;
            for(rg int i=x;i;i=FAQ[i]){
                if(FAQ[i])QUE.pop(Top(FAQ[i]));
                if(FAQ[i])Que[FAQ[i]].pop(que[i].top());
                col[x]?que[i].pop(dist(FAQ[i],x)):que[i].push(dist(FAQ[i],x));
                if(FAQ[i])Que[FAQ[i]].push(que[i].top());
                if(FAQ[i])QUE.push(Top(FAQ[i]));
            }
            QUE.pop(Top(x));
            if(col[x])--tot;else++tot;
            col[x]^=1;
            QUE.push(Top(x));
        }
    }
    return 0;
}

bzoj3730 震波

每个点维护两颗线段树。。。这不看题解咋搞

第一颗存子树对这个点的贡献,下标是子树的点到这个点的距离,存的值是这些点的权值和

第二颗存子树对父亲的贡献,下标是到父亲的距离,存的是这些点的权值和

剩下都看题解写的。。。。。。

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cmath>
#define il inline
#define rg register
#define vd void
#define sta static
using namespace std;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=100001,maxm=maxn<<1;
int n,m,lg,val[maxn];
typedef const int& cni;
namespace sgt{
    const int maxd=20000000;
    int index,root1[maxn],root2[maxn],ls[maxd],rs[maxd],sum[maxd];
#define mid ((l+r)>>1)
    il vd update(int&x,int l,int r,cni p,cni k){
        if(!x)x=++index;sum[x]+=k;
        if(l==r)return;
        if(p<=mid)update(ls[x],l,mid,p,k);
        else update(rs[x],mid+1,r,p,k);
    }
    il int query(cni x,int l,int r,cni R){
        if(!sum[x]||R<l)return 0;
        if(r<=R)return sum[x];
        return query(ls[x],l,mid,R)+query(rs[x],mid+1,r,R);
    }
}

namespace Divide{
    int fir[maxn],dis[maxm],nxt[maxm],id,rt;
    il vd link(cni x,cni y){nxt[++id]=fir[x],fir[x]=id,dis[id]=y;}
    namespace SLPF{
        int dep[maxn],fa[maxn],siz[maxn],top[maxn],son[maxn];
        il vd DFS(cni x){
            siz[x]=1;
            for(int i=fir[x];i;i=nxt[i])
                if(dis[i]^fa[x]){
                    dep[dis[i]]=dep[x]+1,fa[dis[i]]=x;
                    DFS(dis[i]);
                    siz[x]+=siz[dis[i]];
                    if(siz[dis[i]]>siz[son[x]])son[x]=dis[i];
                }
        }
        il vd DFS2(cni x,cni tp){
            top[x]=tp;
            if(son[x])DFS2(son[x],tp);
            for(int i=fir[x];i;i=nxt[i])
                if((dis[i]^fa[x])&&(dis[i]^son[x]))
                    DFS2(dis[i],dis[i]);
        }
        il int dist(int x,int y){
            int ret=dep[x]+dep[y];
            while(top[x]^top[y])
                if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
                else y=fa[top[y]];
            if(dep[y]<dep[x])x=y;
            return ret-dep[x]*2;
        }
    }
    namespace DFZ{
        int f[maxn],siz[maxn],FAQ[maxn],sum,vis[maxn];
        il vd getrt(cni x,cni FA){
            f[x]=0,siz[x]=1;
            for(int i=fir[x];i;i=nxt[i]){
                if(FA==dis[i]||vis[dis[i]])continue;
                getrt(dis[i],x);
                siz[x]+=siz[dis[i]],f[x]=max(f[x],siz[dis[i]]);
            }
            f[x]=max(f[x],sum-siz[x]);
            if(f[x]<f[rt])rt=x;
        }
        il vd Getrt(cni x,cni _sum){f[0]=2e9,sum=_sum,rt=0,getrt(x,-1);}
        il vd Build(int x){
            vis[x]=1;
            for(int i=fir[x];i;i=nxt[i]){
                if(vis[dis[i]])continue;
                Getrt(dis[i],siz[dis[i]]);
                FAQ[rt]=x;Build(rt);
            }
        }
    }
    il int Query(int x,int k){
        int ret=sgt::query(sgt::root1[x],1,n,k+1),yyb=0;
        for(int i=x;DFZ::FAQ[i];i=DFZ::FAQ[i]){
            yyb=SLPF::dist(x,DFZ::FAQ[i]);
            ret+=sgt::query(sgt::root1[DFZ::FAQ[i]],1,n,k-yyb+1);
            ret-=sgt::query(sgt::root2[i],1,n,k-yyb+1);
        }
        return ret;
    }
    il vd Update(int x,int y){
        sgt::update(sgt::root1[x],1,n,1,y);int yyb=0;
        for(int i=x;DFZ::FAQ[i];i=DFZ::FAQ[i]){
            yyb=SLPF::dist(x,DFZ::FAQ[i]);
            sgt::update(sgt::root1[DFZ::FAQ[i]],1,n,yyb+1,y);
            sgt::update(sgt::root2[i],1,n,yyb+1,y);
        }
    }
    il vd Prepare(){
        DFZ::Getrt(1,n);
        SLPF::DFS(1),SLPF::DFS2(1,1);
        DFZ::Build(rt);
        for(rg int i=1;i<=n;++i)Update(i,val[i]);
    }
}
int main(){
#ifdef xzz
    freopen("orz.in","r",stdin);
    freopen("orz.out","w",stdout);
#endif
    int opt,u,v,lst=0;
    n=gi(),m=gi();lg=log2(n);
    for(rg int i=1;i<=n;++i)val[i]=gi();
    for(rg int i=1;i<n;++i)u=gi(),v=gi(),Divide::link(u,v),Divide::link(v,u);
    Divide::Prepare();      
    while(m--){
        opt=gi(),u=gi(),v=gi();
#ifdef ONLINE_JUDGE
        u^=lst,v^=lst;
#endif
        if(opt==0)lst=Divide::Query(u,v),printf("%d\n",lst);
        else Divide::Update(u,v-val[u]),val[u]=v;
    }
    return 0;
}

bzoj4372 烁烁的游戏

我™放弃了。。。

哪天想起来了再补吧

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=maxm;
typedef const int& ci;
int n,m;
namespace sgt{
    int maxd=2e7;
    int ls[maxd],rs[maxd],sum[maxd],idx;
#define mid ((l+r)>>1)
    il vd update(int&x,int l,int r,ci p,ci k){
        if(!x)x=++idx;sum[x]+=k;
        if(l==r)return;
        if(mid<p)update(rs[x],mid+1,r,p,k);
        else update(ls[x],l,mid,p,k);
    }
    il int query(ci x,int l,int r,ci L,ci R){
        if(!sum[x]||R<l||r<L)return 0;
        if(L<=l&&r<=R)return sum[x];
        return query(ls[x],l,mid,L,R)+query(rs[x],mid+1,r,L,R);
    }
#undef mid
}
namespace Tree{
    int fir[maxn],nxt[maxn<<1],dis[maxn<<1],idx;
    il vd link(ci x,ci y){nxt[++id]=fir[x],fir[x]=id,dis[id]=y;}
    namespace SLPF{
        int root[maxn],root2[maxn],siz[maxn],dep[maxn],fa[maxn],son[maxn],top[maxn];
        il vd dfs(ci x){
            siz[x]=1;
            for(int i=fir[x];i;i=nxt[i]){
                if(fa[x]==i)continue;
                fa[dis[i]]=x;
                dep[dis[i]]=dep[x]+1;
                dfs(dis[i]);
                if(siz[dis[i]]>siz[son[x]])son[x]=dis[i];
            }
        }
        il vd dfs2(ci x,ci tp){
            top[x]=tp;
            if(son[x])dfs2(son[x],tp);
            for(int i=fir[x];i;i=nxt[i]){
                if(fa[x]==i||son[x]==i)continue;
                dfs2(dis[i],dis[i]);
            }
        }
        il int dist(int x,int y){
            int ret=dep[x]+dep[y];
            while(top[x]^top[y])
                if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
                else y=fa[top[y]];
            if(dep[x]>dep[y])x=y;
            return ret-dep[x]*2;
        }
    }namespace DFZ{
        int siz[maxn],f[maxn],rt,sum;bool vis[maxn];
        il vd getrt(ci x,ci FA){
            siz[x]=1,f[x]=0;
            for(int i=fir[x];i;i=nxt[i]){
                if(FA==dis[i]||vis[dis[i]])continue;
                getrt(dis[i],x);
                siz[x]+=siz[dis[i]];
                f[x]=max(f[x],siz[dis[i]]);
            }
            f[x]=max(f[x],sum-siz[dis[i]]);
            if(f[x]<f[rt])rt=x;
        }
        il vd Getrt(ci x,ci _sum){f[0]=2e9,rt=0,sum=_sum,getrt(x,-1);}
        il vd build(ci x){
            vis[x]=1;
            for(int i=fir[x];i;i=nxt[i]){
                if(vis[dis[i]])continue;
                Getrt(dis[i],siz[dis[i]]);
                FAQ[rt]=x;
                build(rt);
            }
        }
    }
    il vd prepare(){
        int u,v;
        for(rg int i=1;i<n;++i)u=gi(),v=gi(),link(u,v),link(v,u);
        DFZ::Getrt(1,n),DFZ::build(DFZ::rt);
        SLPF::dfs(1),SLPF::dfs2(1);
    }
    il vd Update(int x,int d,int w){
        sgt::update(root[x],1,n,d+1,w);
        for(rg int i=FAQ[x];FAQ[i];i=FAQ[i]){
            int dst=SLPF::dist(x,FAQ[i]);
            sgt::update(sgt::root[FAQ[i]],1,n,1,w);
            sgt::update(sgt::root2[i],1,n,1,w);
            sgt::update(sgt::root[FAQ[i]],1,n,dst+2,-w);
            sgt::update(sgt::root2[i],1,n,dst+2,-w);
        }
    }
    il int Query(int x){
        int ret=sgt::query(root[x],);
    }
}
int main(){
    freopen("orz.in","r",stdin);
    freopen("orz.out","w",stdout);
    n=gi(),m=gi();
    
    return 0;
}

转载于:https://www.cnblogs.com/xzz_233/p/8301050.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值