Description
N个点,形成一个树状结构。有M次发放,每次选择两个点x,y
对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成
所有发放后,每个点存放最多的是哪种物品。
Input
第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题
Output
输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品
则输出0
离线处理,树链剖分将树展开为链,然后对操作记录差分(当前点比上一个点多了、少了哪些物品)
最后扫一遍处理出答案
#include<cstdio> #include<algorithm> #include<vector> int read(){ int x=0,c=getchar(); while(c<48)c=getchar(); while(c>47)x=x*10+c-48,c=getchar(); return x; } const int N=100010; int n,m; int et[N*2],enx[N*2],e0[N],ep=2; int sz[N],dep[N],fa[N],pf[N],top[N],id[N],idr[N],idp=0; int q[N][3],vs[N],t[N],tr[262144],ans[N]; std::vector<int> _i[N],_d[N]; void f1(int w,int pa){ dep[w]=dep[fa[w]=pa]+1; sz[w]=1; for(int i=e0[w];i;i=enx[i]){ int u=et[i]; if(u==pa)continue; f1(u,w); sz[w]+=sz[u]; if(sz[u]>sz[pf[w]])pf[w]=u; } } void f2(int w,int tp){ idr[id[w]=++idp]=w; top[w]=tp; if(pf[w])f2(pf[w],tp); for(int i=e0[w];i;i=enx[i]){ int u=et[i]; if(u!=fa[w]&&u!=pf[w])f2(u,u); } } void ins(int x,int y,int z){ int a=top[x],b=top[y],c; while(a!=b){ if(dep[a]<dep[b])c=a,a=b,b=c,c=x,x=y,y=c; _i[id[a]].push_back(z); _d[id[x]].push_back(z); x=fa[a];a=top[x]; } if(dep[x]>dep[y])c=x,x=y,y=c; _i[id[x]].push_back(z); _d[id[y]].push_back(z); } void _ins(int x){ ++t[x]; int w=x+131072; tr[w]=x; for(w>>=1;w;w>>=1){ int a=w<<1,b=a^1; tr[w]=t[tr[b]]>t[tr[a]]?tr[b]:tr[a]; } } void _del(int x){ int w=x+131072; if(!--t[x])tr[w]=0; for(w>>=1;w;w>>=1){ int a=w<<1,b=a^1; tr[w]=t[tr[b]]>t[tr[a]]?tr[b]:tr[a]; } } int main(){ n=read();m=read(); for(int i=1;i<n;i++){ int a=read(),b=read(); et[ep]=b;enx[ep]=e0[a];e0[a]=ep++; et[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } f1(1,0);f2(1,1); for(int i=0;i<m;i++){ q[i][0]=read(); q[i][1]=read(); vs[i]=q[i][2]=read(); } std::sort(vs,vs+m); for(int i=0;i<m;i++){ ins(q[i][0],q[i][1],std::lower_bound(vs,vs+m,q[i][2])-vs+1); } for(int i=1;i<=n;i++){ for(int j=0;j<_i[i].size();j++)_ins(_i[i][j]); ans[idr[i]]=tr[1]?vs[tr[1]-1]:0; for(int j=0;j<_d[i].size();j++)_del(_d[i][j]); } for(int i=1;i<=n;i++)printf("%d\n",ans[i]); return 0; }