树的分治及动态树分治

orz hhw posted @ 2015年5月12日 20:13 in 算法学习 with tags 树分治 算法学习 模板 动态树分治 , 5373 阅读

数据结构最后一个基础算法了、、总算开始学了

先阅读了《分治算法在树的路径问题中的应用》,好不容易找到不要钱的

然后按照上面讲的一步一步写下来

树的重心模板(POJ1655)

#include<cstdio>
#include<iostream>
#include<cstring>
#define N 111111
using namespace std;
int T,n,i,x,y,root,ans,tot,first[N],mav[N],size[N],next[N<<1],last[N<<1];
bool vis[N];
void insert(int x,int y){last[++tot]=y;next[tot]=first[x];first[x]=tot;}
void dfs(int x){
	size[x]=1;mav[x]=0;
	for(int i=first[x];i;i=next[i]){
		int y=last[i];
		if(!vis[y]){
			vis[y]=1;
			dfs(y);
			size[x]+=size[y];
			mav[x]=max(mav[x],size[y]);
		}
	}
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		memset(first,0,sizeof(first));
		memset(vis,0,sizeof(vis));
		tot=0;
		for(i=1;i<n;i++)scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
		vis[1]=1;dfs(1);
		ans=99999999;root=0;
		for(i=1;i<=n;i++){
			mav[i]=max(mav[i],n-size[i]);
			if(mav[i]<ans)ans=mav[i],root=i;
		}
		printf("%d %d\n",root,ans);
	}
}

【例1】POJ1741(给一棵边带权树,问两点之间的距离小于等于K的点对有多少个)

一路分治下来,每次选重心点算每个点到重心点的距离,统计一下<=K的路径条数,再减去从同一子节点弄上来的两条路径,复杂度O(n log^2n)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define N 11111
using namespace std;
int n,k,i,x,y,z,ans,root,tot,top,val,next[N<<1],last[N<<1],value[N<<1],first[N],size[N],mav[N],num[N];
bool vis[N];
void insert(int x,int y,int z){last[++tot]=y;next[tot]=first[x];value[tot]=z;first[x]=tot;}
void dfssize(int x,int fa){//第一遍遍历
	size[x]=1;mav[x]=0;
	for(int i=first[x];i;i=next[i]){
		int y=last[i];
		if(y!=fa&&!vis[y]){
			dfssize(y,x);
			size[x]+=size[y];
			mav[x]=max(mav[x],size[y]);
		}
	}
}
void dfsroot(int zs,int x,int fa){//求重心
	if(size[zs]-size[x]>mav[x])mav[x]=size[zs]-size[x];
	if(mav[x]<val)val=mav[x],root=x;
	for(int i=first[x];i;i=next[i])
		if(last[i]!=fa&&!vis[last[i]])dfsroot(zs,last[i],x);
}
void dfsdis(int x,int fa,int dis){//统计距离
	num[++top]=dis;
	for(int i=first[x];i;i=next[i]){
		int y=last[i];
		if(y!=fa&&!vis[y])dfsdis(y,x,dis+value[i]);
	}
}
int calc(int x,int co){
	int now=0,i,j;top=0;
	dfsdis(x,0,co);
	sort(num+1,num+top+1);//统计出所有路径的条数并排序
	for(i=1,j=top;i<j;i++){//处理出<=k的路径条数
		while(num[i]+num[j]>k&&i<j)j--;
		now+=(j-i);
	}
	return now;
}
void dfs(int x){
	val=99999999;
	dfssize(x,0);
	dfsroot(x,x,0);//求出树的重心
	ans+=calc(root,0);//统计以重心为根所有路径符合条件的个数
	vis[root]=1;
	for(int i=first[root];i;i=next[i]){
		int y=last[i];
		if(!vis[y]){
			ans-=calc(y,value[i]);//减去从同一子节点上来的路径
			dfs(y);
		}
	}
}
int main(){
	while(1){
		scanf("%d%d",&n,&k);
		if(!n&&!k)return 0;
		memset(first,0,sizeof(first));memset(vis,0,sizeof(vis));tot=0;ans=0;
		for(i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),insert(x,y,z),insert(y,x,z);
		dfs(1);
		printf("%d\n",ans);
	}
}

BZOJ2152聪聪可可:点分治,同上

#include<cstdio>
#include<iostream>
#define N 22222
#define inf 99999999
using namespace std;
int n,i,x,y,z,tot,val,root,ans,fm,gy,num[3],last[N<<1],value[N<<1],next[N<<1],first[N],mav[N],size[N];
bool vis[N];
int gcd(int x,int y){if(!x)return y;return gcd(y%x,x);}
void insert(int x,int y,int z){last[++tot]=y;value[tot]=z;next[tot]=first[x];first[x]=tot;}
void dfssize(int x,int fa){
	size[x]=1;mav[x]=0;
	for(int i=first[x];i;i=next[i]){
		int y=last[i];
		if(y!=fa&&!vis[y])dfssize(y,x),size[x]+=size[y],mav[x]=max(mav[x],size[y]);
	}
}
void dfsroot(int g,int x,int fa){
	if(size[g]-size[x]>mav[x])mav[x]=size[g]-size[x];
	if(mav[x]<val)val=mav[x],root=x;
	for(int i=first[x];i;i=next[i])
		if(last[i]!=fa&&!vis[last[i]])dfsroot(g,last[i],x);
}
void dfsdis(int x,int fa,int dis){
	num[dis]++;
	for(int i=first[x];i;i=next[i]){
		int y=last[i];
		if(y!=fa&&!vis[y])dfsdis(y,x,(dis+value[i])%3);
	}
}
int calc(int x,int co){
	num[0]=num[1]=num[2]=0;
	dfsdis(x,0,co);
	return num[0]*num[0]+num[1]*num[2]*2;
}
void dfs(int x){
	val=inf;
	dfssize(x,0);
	dfsroot(x,x,0);
	ans+=calc(root,0);
	vis[root]=1;
	for(int i=first[root];i;i=next[i]){
		int y=last[i];
		if(!vis[y])ans-=calc(y,value[i]),dfs(y);
	}
}
int main(){
	scanf("%d",&n);
	for(i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),z%=3,insert(x,y,z),insert(y,x,z);
	dfs(1);
	fm=n*n;gy=gcd(ans,fm);
	ans/=gy;fm/=gy;
	printf("%d/%d",ans,fm);
}♀大

BZOJ1758 首先二分答案转变为判断可行性问题,对于一个分治结构,得到其一个子树下所有深度的最好值,和当前的最好值进行正反两遍单调队列,分别表示i-R+L~i的值和i~i+R-L的值,这样就可以保证时间复杂度为O(nlgnlg1e9)

#include<bits/stdc++.h>
#define N 100100
#define inf -1e17
using namespace std;
int n,i,L,R,x,y,h,t,rt,tot,fir[N],Fir[N],mv[N],sz[N],q[N],la[N<<2],ne[N<<2];
double l,r,mid,ans,z,va[N<<2],a[N],b[N];bool vis[N],ff;
void ins(int x,int y,double z){la[++tot]=y;va[tot]=z;ne[tot]=fir[x];fir[x]=tot;}
void Ins(int x,int y){la[++tot]=y;va[tot]=z;ne[tot]=Fir[x];Fir[x]=tot;}
void dsz(int x,int fa){
	sz[x]=1;mv[x]=0;
	for(int i=fir[x],y;i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)dsz(y,x),sz[x]+=sz[y],mv[x]=max(mv[x],sz[y]);
}
void drt(int zs,int x,int fa,int &rt){
	mv[x]=max(mv[x],sz[zs]-sz[x]);if(mv[x]<mv[rt]||!rt)rt=x;
	for(int i=fir[x];i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)drt(zs,y,x,rt);
}
int fz(int x){
	int i,p,rt=0;dsz(x,0);drt(x,x,0,rt);vis[rt]=1;
	for(i=fir[rt];i;i=ne[i])if(!vis[la[i]])Ins(rt,fz(la[i]));
	return rt;
}
void tour(int x,int fa,int dp,double w,double z,int&de){
	b[dp]=max(b[dp],w);de=max(de,dp);
	for(int i=fir[x];i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)tour(la[i],x,dp+1,w+va[i]-z,z,de);
}
void get(int x,double z){
	if(ans>0)return;int i,j,h,t,de,st=0;vis[x]=1;
	for(i=fir[x];i;i=ne[i])if(!vis[la[i]]){
		de=t=0;h=1;tour(la[i],x,1,va[i]-z,z,de);st=max(st,de);
		for(j=0;j<=de;j++){
			for(;h<=t&&q[h]<j-R+L;h++);
			for(;h<=t&&b[j]>=b[q[t]];t--);
			q[++t]=j;ans=max(ans,a[R-j]+b[q[h]]);
			if(ans>0)return;
		}
		for(t=0,h=1,j=de;j>=0;j--){
			for(;h<=t&&q[h]>j+R-L;h++);
			for(;h<=t&&b[j]>=b[q[t]];t--);
			q[++t]=j;ans=max(ans,a[L-j]+b[q[h]]);
			if(ans>0)return;
		}
		for(j=1;j<=de;j++)a[j]=max(a[j],b[j]),b[j]=inf;
	}
	for(i=1;i<=st;i++)a[i]=inf;
	for(i=Fir[x];i;i=ne[i])get(la[i],z);
}
bool ok(double z){memset(vis,0,sizeof(vis));ans=inf;for(i=1;i<=n;i++)a[i]=b[i]=inf;get(rt,z);return ans>0;}
int main(){
	for(scanf("%d%d%d",&n,&L,&R),i=1;i<n;i++)scanf("%d%d%lf",&x,&y,&z),ins(x,y,z),ins(y,x,z);
	for(rt=fz(1),l=0,r=1000000;r-l>1e-5;)if(ok(mid=(l+r)/2))l=mid;else r=mid;
	printf("%.3lf",l);
}

今天第N次看动态树分治,总算看懂了。。

大概就是像点分治一样先维护出一颗重心树来,然后每个点用数据结构维护

BZOJ1095

对于每个点,用A[]记录该点子树中所有点到其距离,用B[]记录各个儿子A[]的最大值,用C记录全局B的最大值和次大值,每次的答案就是C的最大值

对于修改操作,只会修改一条链,那么在这条链上修改所有的A[]、B[]并更新C[]就可以了

#include<bits/stdc++.h>
#define N 100100
using namespace std;char s[9];
int n,m,i,x,y,tot,cnt,fir[N],d[N],sz[N],mv[N],ne[N<<1],la[N<<1],F[N][17],fa[N];bool vis[N],co[N];
multiset<int>A[N],B[N],C;multiset<int>::iterator it;
void ins(int x,int y){la[++tot]=y;ne[tot]=fir[x];fir[x]=tot;}
void Ins(multiset<int>a){if(a.size()>=2)it=--a.end(),C.insert(*it+(*--it));}
void Del(multiset<int>a){if(a.size()>=2)it=--a.end(),C.erase(C.find(*it+(*--it)));}
void dfs(int x){
	for(int i=1;i<=16;i++)F[x][i]=F[F[x][i-1]][i-1];
	for(int i=fir[x];i;i=ne[i])if(F[x][0]!=la[i])d[la[i]]=d[x]+1,F[la[i]][0]=x,dfs(la[i]);
}
void dsz(int x,int fa){
	sz[x]=1;mv[x]=0;
	for(int i=fir[x],y;i;i=ne[i])if(!vis[y=la[i]]&&y!=fa){
		dsz(y,x);sz[x]+=sz[y];mv[x]=max(mv[x],sz[y]);
	}
}
void drt(int zs,int x,int fa,int &rt){
	mv[x]=max(mv[x],sz[zs]-sz[x]);
	if(mv[x]<mv[rt]||!rt)rt=x;
	for(int i=fir[x];i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)drt(zs,y,x,rt);
}
void get(int x,int fa,int de,multiset<int>&s){
	s.insert(de);
	for(int i=fir[x];i;i=ne[i])if(!vis[la[i]]&&la[i]!=fa)get(la[i],x,de+1,s);
}
int fz(int x){
	int i,p,rt=0;dsz(x,0);drt(x,x,0,rt);vis[rt]=1;
	B[rt].insert(0);
	for(i=fir[rt];i;i=ne[i])if(!vis[la[i]]){
		multiset<int>s;get(la[i],0,1,s);
		p=fz(la[i]);fa[p]=rt;A[p]=s;
		B[rt].insert(*--A[p].end());
	}
	Ins(B[rt]);return rt;
}
int lca(int x,int y){
    if(d[x]<d[y])swap(x,y);int t=d[x]-d[y],i;
    for(i=0;i<=16;i++)if(t&(1<<i))x=F[x][i];
    for(i=16;i>=0;i--)if(F[x][i]!=F[y][i])x=F[x][i],y=F[y][i];
    return x==y?x:F[x][0];
}
int dis(int x,int y){return d[x]+d[y]-2*d[lca(x,y)];}
void cha(int x,bool f){
	Del(B[x]);if(f)B[x].erase(B[x].find(0));else B[x].insert(0);Ins(B[x]);
	for(int i=x,y;fa[i];i=fa[i]){
		Del(B[y=fa[i]]);
		if(A[i].size())B[y].erase(B[y].find(*--A[i].end()));
		if(f)A[i].erase(A[i].find(dis(y,x)));else A[i].insert(dis(y,x));
		if(A[i].size())B[y].insert(*--A[i].end());
		Ins(B[y]);
	}
}
int main(){
	for(scanf("%d",&n),cnt=n,i=1;i<n;i++)scanf("%d%d",&x,&y),ins(x,y),ins(y,x);
	for(dfs(1),fz(1),scanf("%d",&m);m--;){
		scanf("%s",s);
		if(s[0]=='G')if(cnt<=1)printf("%d\n",cnt-1);else printf("%d\n",*--C.end());
		else scanf("%d",&x),co[x]^=1,cha(x,co[x]);
	}
}

BZOJ3924 就是省选题。先弄出分治树,然后更新答案在分治出来的树上更新,维护每个分治树内的答案和对外面的影响,预处理LCA,O(1)询问,总时间复杂度O(knlg^2n)

#include<bits/stdc++.h>
#define N 100100
using namespace std;typedef long long LL;LL F[N<<1][18],d[N],s1[N],s2[N],w1[N],w2[N];bool vis[N];
int n,m,i,j,x,y,z,mt,rt,tot,gl[N<<1],fir[N],Fir[N],mv[N],sz[N],fa[N],la[N<<2],ne[N<<2],va[N<<2],pos[N];
void ins(int x,int y,int z){la[++tot]=y;ne[tot]=fir[x];va[tot]=z;fir[x]=tot;}
void Ins(int x,int y,int z){la[++tot]=y;ne[tot]=Fir[x];va[tot]=z;Fir[x]=tot;fa[z]=x;}
void dfs(int x,int fa){
	F[pos[x]=++mt][0]=d[x];
	for(int i=fir[x];i;i=ne[i])if(la[i]!=fa)d[la[i]]=d[x]+va[i],dfs(la[i],x),F[++mt][0]=d[x];
}
void dsz(int x,int fa){
	sz[x]=1;mv[x]=0;
	for(int i=fir[x],y;i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)dsz(y,x),sz[x]+=sz[y],mv[x]=max(mv[x],sz[y]);
}
void drt(int zs,int x,int fa,int&rt){
	mv[x]=max(mv[x],sz[zs]-sz[x]);if(mv[x]<mv[rt]||!rt)rt=x;
	for(int i=fir[x];i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)drt(zs,y,x,rt);
}
int fz(int x){
	int i,p,rt=0;dsz(x,0);drt(x,x,0,rt);vis[rt]=1;
	for(i=fir[rt];i;i=ne[i])if(!vis[la[i]])Ins(rt,la[i],fz(la[i]));
	return rt;
}
int dis(int x,int y){
	int w=d[x]+d[y],t;x=pos[x];y=pos[y];
	if(x>y)swap(x,y);t=gl[y-x+1];
	return w-2*min(F[x][t],F[y-(1<<t)+1][t]);
}
LL add(int x,int z){
	s1[x]+=z;
	for(int i=x,y;fa[i];i=fa[i])y=dis(fa[i],x),w1[fa[i]]+=(LL)y*z,w2[i]+=(LL)y*z,s1[fa[i]]+=z,s2[i]+=z;
}
LL cal(int x){
	LL ans=w1[x];
	for(int i=x,y;fa[i];i=fa[i])y=dis(fa[i],x),ans+=(w1[fa[i]]-w2[i]+(s1[fa[i]]-s2[i])*y);
	return ans;
}
LL qu(int x){
	LL ans=cal(x),w;
	for(int i=Fir[x];i;i=ne[i]){
		w=cal(la[i]);
		if(w<ans)return qu(va[i]);
	}
	return ans;
}
int main(){
	for(scanf("%d%d",&n,&m),i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),ins(x,y,z),ins(y,x,z);
	for(dfs(1,0),i=2;i<=mt;i++)gl[i]=gl[i>>1]+1;
	for(j=1;j<=gl[mt];j++)for(i=1;i+(1<<j)-1<=mt;i++)F[i][j]=min(F[i][j-1],F[i+(1<<j-1)][j-1]);
	for(rt=fz(1);m--;printf("%lld\n",qu(rt)))scanf("%d%d",&x,&z),add(x,z);
}

BZOJ3730 辣鸡卡常题

#include<bits/stdc++.h>
#define N 101000
using namespace std;typedef long long LL;bool v[N];LL ans,sm[N*60];
int n,Q,i,j,o,x,y,z,rt,id,di,tot,a[N],fir[N],ne[N*2],la[N*2],F[N],G[N*2][18],f[N],sz[N],d[N],pos[N],gl[N*2],A[N],B[N],L[N*60],R[N*60];
char ch;inline void Z(int &x){
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    for(x=0;ch>='0';ch=getchar())x=x*10+ch-'0';
}
inline void ins(int x,int y){la[++tot]=y;ne[tot]=fir[x];fir[x]=tot;}
inline void dfs(int x,int fa){
	G[pos[x]=++id][0]=d[x];
	for(int i=fir[x];i;i=ne[i])if(la[i]!=fa)d[la[i]]=d[x]+1,dfs(la[i],x),G[++id][0]=d[x];
}
inline int dis(int x,int y){
	int w=d[x]+d[y],t;x=pos[x];y=pos[y];
	if(x>y)swap(x,y);t=gl[y-x+1];
	return w-2*min(G[x][t],G[y-(1<<t)+1][t]);
}
inline void dsz(int x,int fa){
	sz[x]=1;f[x]=0;
	for(int i=fir[x],y;i;i=ne[i])if(!v[y=la[i]]&&y!=fa)dsz(y,x),sz[x]+=sz[y],f[x]=max(f[x],sz[y]);
}
inline void drt(int zs,int x,int fa,int&rt){
	f[x]=max(f[x],sz[zs]-sz[x]);if(f[x]<f[rt]||!rt)rt=x;
	for(int i=fir[x];i;i=ne[i])if(!v[y=la[i]]&&y!=fa)drt(zs,y,x,rt);
}
inline void ins(int&k,int l,int r,int x,int z){
	if(!k)k=++di;sm[k]+=z;if(l==r)return;int M=l+r>>1;
	if(x<=M)ins(L[k],l,M,x,z);else ins(R[k],M+1,r,x,z);
}
inline LL qu(int k,int l,int r,int x){
	if(!k||x<l)return 0;if(r<=x)return sm[k];int M=l+r>>1;
	return qu(L[k],l,M,x)+qu(R[k],M+1,r,x);
}
inline void cal(int x,int fa,int E,int&rt){
	ins(rt,0,n,dis(x,E),a[x]);
	for(int i=fir[x],y;i;i=ne[i])if(!v[y=la[i]]&&y!=fa)cal(y,x,E,rt);
}
inline int fz(int x,int fa){
	int i,R=0,y,p;dsz(x,0);drt(x,x,0,R);cal(R,0,R,A[R]);v[R]=1;F[R]=fa;
	for(i=fir[R];i;i=ne[i])if(!v[y=la[i]])cal(y,R,R,p=0),B[fz(y,R)]=p;
	return R;
}
inline void cha(int x,int z){
	ins(A[x],0,n,0,z);
	for(int i=x,o;F[i];i=F[i])o=dis(x,F[i]),ins(A[F[i]],0,n,o,z),ins(B[i],0,n,o,z);
}
inline LL qu(int x,int k){
	LL V=qu(A[x],0,n,k);int i=x,o;
	for(;F[i];i=F[i])o=dis(x,F[i]),V+=qu(A[F[i]],0,n,k-o)-qu(B[i],0,n,k-o);
	return V;
}
int main(){
	for(Z(n),Z(Q),i=1;i<=n;i++)Z(a[i]);
	for(i=1;i<n;i++)Z(x),Z(y),ins(x,y),ins(y,x);
	for(dfs(1,0),i=2;i<=id;i++)gl[i]=gl[i>>1]+1;
	for(j=1;j<=gl[id];j++)for(i=1;i+(1<<j)-1<=id;i++)G[i][j]=min(G[i][j-1],G[i+(1<<j-1)][j-1]);
	for(rt=fz(1,0);Q--;)
		if(Z(o),Z(x),Z(y),x^=ans,y^=ans,o)z=y-a[x],a[x]=y,cha(x,z);else ans=qu(x,y),printf("%lld\n",ans);
}

BZOJ2051&4317 先一遍树分治,得到一个距离序列,用vector记录并排序,然后对每个点统计答案时二分+判定,判定时候再二分,总复杂度O(nlg^3n)

#include<bits/stdc++.h>
#define N 15050
using namespace std;vector<int>v1[N],v2[N];bool vis[N];
int n,k,i,x,y,z,D,l,r,mid,rt,tot,sz[N],mv[N],fa[N],d[N],h[N],F[N][14],fir[N],ne[N<<1],la[N<<1],va[N<<1];
void ins(int x,int y,int z){la[++tot]=y;va[tot]=z;ne[tot]=fir[x];fir[x]=tot;}
void dfs(int x,int fa){
	for(int i=1;i<=13;i++)F[x][i]=F[F[x][i-1]][i-1];
	for(int i=fir[x],y;i;i=ne[i])if(la[i]!=fa)F[y=la[i]][0]=x,h[y]=h[x]+1,d[y]=d[x]+va[i],dfs(y,x);
}
int lca(int x,int y){
    if(h[x]<h[y])swap(x,y);int t=h[x]-h[y],i;
    for(i=0;i<=13;i++)if(t>>i&1)x=F[x][i];
    for(i=13;i>=0;i--)if(F[x][i]!=F[y][i])x=F[x][i],y=F[y][i];
    return x==y?x:F[x][0];
}
int dis(int x,int y){return d[x]+d[y]-2*d[lca(x,y)];}
void dsz(int x,int fa){
    sz[x]=1;mv[x]=0;
    for(int i=fir[x],y;i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)dsz(y,x),sz[x]+=sz[y],mv[x]=max(mv[x],sz[y]);
}
void drt(int zs,int x,int fa,int&rt){
    mv[x]=max(mv[x],sz[zs]-sz[x]);if(mv[x]<mv[rt]||!rt)rt=x;
    for(int i=fir[x],y;i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)drt(zs,y,x,rt);
}
void get(int x,int fa,int z,vector<int>&w){
	w.push_back(z);
	for(int i=fir[x],y;i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)get(y,x,z+va[i],w);
}
int fz(int x){
    int i,p,rt=0;dsz(x,0);drt(x,x,0,rt);vis[rt]=1;get(rt,0,0,v1[rt]);
    for(i=fir[rt];i;i=ne[i])if(!vis[la[i]]){
    	vector<int>o;get(la[i],rt,va[i],o);
		fa[p=fz(la[i])]=rt;v2[p]=o;
	}
	return rt;
}
int ask(int w,int z){
	int l=1,r=v1[w].size(),mid,ans=0;
	for(;l<=r;)if(mid=l+r>>1,z>=v1[w][mid-1])ans=mid,l=mid+1;else r=mid-1;
	return ans;
}
int ask2(int w,int z){
	int l=1,r=v2[w].size(),mid,ans=0;
	for(;l<=r;)if(mid=l+r>>1,z>=v2[w][mid-1])ans=mid,l=mid+1;else r=mid-1;
	return ans;
}
int cal(int x,int z){
	int now=ask(x,z),i=x;
	for(;fa[i];i=fa[i])D=dis(x,fa[i]),now+=ask(fa[i],z-D)-ask2(i,z-D);
	return now;
}
int qu(int x){
	for(l=0,r=10*n;l<r;)if(cal(x,mid=l+r>>1)<=k)l=mid+1;else r=mid;
	return l;
}
int main(){
	for(scanf("%d%d",&n,&k),i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),ins(x,y,z),ins(y,x,z);
	for(dfs(1,0),rt=fz(1),i=1;i<=n;i++)sort(v1[i].begin(),v1[i].end()),sort(v2[i].begin(),v2[i].end());
	for(i=1;i<=n;i++)printf("%d\n",qu(i));
}

BZOJ2566 动态树分治+map套set

#include<bits/stdc++.h>
#define N 12121
using namespace std;bool vis[N];multiset<int>A[N],B[N],C[N];
struct W{
    multiset<int>A,B;
    int G(){
        if(A.size()<2)return 1e9;int x=*A.begin();
        multiset<int>::iterator it=A.begin();return x+(*++it);
    }
};map<int,W>mp[N];map<int,W>::iterator it;multiset<int>U;
int n,m,i,j,x,y,z,rt,tot,id,c[N],d[N],h[N],fir[N],ne[N*2],la[N*2],va[N*2],F[N][14],mv[N],sz[N],fa[N],q[N];
void D(multiset<int>&S,int x){S.erase(S.find(x));}
void ins(int x,int y,int z){la[++tot]=y;va[tot]=z;ne[tot]=fir[x];fir[x]=tot;}
void dfs(int x,int fa){
    for(int i=1;i<14;i++)F[x][i]=F[F[x][i-1]][i-1];
    for(int i=fir[x],y;i;i=ne[i])if(la[i]!=fa)F[y=la[i]][0]=x,h[y]=h[x]+1,d[y]=d[x]+va[i],dfs(y,x);
}
int lca(int x,int y){
    if(h[x]<h[y])swap(x,y);int t=h[x]-h[y],i;
    for(i=0;i<14;i++)if(t>>i&1)x=F[x][i];
    for(i=13;i>=0;i--)if(F[x][i]!=F[y][i])x=F[x][i],y=F[y][i];
    return x==y?x:F[x][0];
}
int dis(int x,int y){return d[x]+d[y]-2*d[lca(x,y)];}
void dsz(int x,int fa){
    sz[x]=1;mv[x]=0;
    for(int i=fir[x],y;i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)dsz(y,x),sz[x]+=sz[y],mv[x]=max(mv[x],sz[y]);
}
void drt(int zs,int x,int fa,int &rt){
    mv[x]=max(mv[x],sz[zs]-sz[x]);if(mv[x]<mv[rt]||!rt)rt=x;
    for(int i=fir[x];i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)drt(zs,y,x,rt);
}
void get(int x,int fa,int z,int rt){
    if(mp[rt].count(c[x]))mp[rt][c[x]].A.insert(z);else {W o;o.A.insert(z);mp[rt][c[x]]=o;}
    for(int i=fir[x],y;i;i=ne[i])if(!vis[y=la[i]]&&y!=fa)get(y,x,z+va[i],rt);
}
int fz(int x){
    int i,p,rt=0;dsz(x,0);drt(x,x,0,rt);vis[rt]=1;
    for(get(rt,0,0,rt),it=mp[rt].begin();it!=mp[rt].end();it++)it->second.B.insert(it->second.G());
    for(i=fir[rt];i;i=ne[i])if(!vis[la[i]])for(p=fz(la[i]),fa[p]=rt,it=mp[p].begin();it!=mp[p].end();it++)mp[rt][it->first].B.insert(*(it->second.B.begin()));
    return rt;
}
void add(int x,int z,int lx){
    if(mp[rt].count(z))D(U,*mp[rt][z].B.begin());
    int t=0,u=x,i;
    for(;u;u=fa[u])q[++t]=u;
    for(i=t;i>1;i--)if(mp[q[i-1]].count(z))D(mp[q[i]][z].B,*mp[q[i-1]][z].B.begin());
    if(lx)for(i=1;i<=t;i++)if(mp[q[i]].count(z))D(mp[q[i]][z].B,mp[q[i]][z].G());
    for(i=x;i;i=u){
        if(lx)mp[i][z].A.insert(dis(x,i));else D(mp[i][z].B,mp[i][z].G()),D(mp[i][z].A,dis(x,i));
        mp[i][z].B.insert(mp[i][z].G());if(u=fa[i])mp[u][z].B.insert(*mp[i][z].B.begin());
    }
    U.insert(*mp[rt][z].B.begin());
}
int main(){
    for(scanf("%d",&n),i=1;i<=n;i++)scanf("%d",&c[i]);
    for(i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),ins(x,y,z),ins(y,x,z);
    for(dfs(1,0),rt=fz(1),it=mp[rt].begin();it!=mp[rt].end();it++)U.insert(*(it->second.B.begin()));
    for(printf("%d\n",*(U.begin())),scanf("%d",&m);m--;printf("%d\n",*(U.begin())))scanf("%d%d",&x,&y),add(x,c[x],0),add(x,y,1),c[x]=y;
}
Avatar_small
nbdhhzh 说:
2015年6月17日 06:50

点分树的重心不用二进制贪心找有希望。。?那是O(n)的你服不服


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter