动态点分治总结

动态点分治总结

下面是伟大の分割线!

上面是伟大の分割线!

废话

再开一坑。

刷几道题来填。

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

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

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

下面是伟大の分割线!

上面是伟大の分割线!

思想

前置技能:点分治。

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

如果每次单点修改之后重新点分治一遍,被影响到的节点最多\(\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;
}
posted @ 2018-01-17 09:29  菜狗xzz  阅读(252)  评论(0编辑  收藏  举报