树的分治及动态树分治
数据结构最后一个基础算法了、、总算开始学了
先阅读了《分治算法在树的路径问题中的应用》,好不容易找到不要钱的
然后按照上面讲的一步一步写下来
树的重心模板(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;
}
2015年6月17日 06:50
点分树的重心不用二进制贪心找有希望。。?那是O(n)的你服不服