首先村落里的一共有n座房屋,并形成一个树状结构。然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x
到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮。然后深绘里想知道,当所有的救济粮发放完毕后,每
座房子里存放的最多的是哪种救济粮。
1 <= n, m <= 100000, 1 <= a, b, x, y <= n, 1 <= z <= 100000
//针对每个给出的树上的点,建立一个权值线段树,动态开点 //权值线段树的叶子点,代表这个树上的点所存放的东西,及数量 #include<bits/stdc++.h> #define mid ((l+r)>>1) using namespace std; const int N=100000+2; const int U=100001; int n,m; struct haha { int nxt,to; }e[2*N]; int hd[N],cnt; void add(int x,int y) { e[++cnt].nxt=hd[x]; e[cnt].to=y; hd[x]=cnt; } int fa[N][18]; int dep[N]; int ans[N]; void dfs(int x,int d) { dep[x]=d;//x的深度为d,根结点深度为1 for(int i=hd[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa[x][0]) continue; fa[y][0]=x; dfs(y,d+1); } } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int j=17;j>=0;j--) { if(dep[fa[x][j]]>=dep[y]) x=fa[x][j]; } if(x==y) return x; for(int j=17;j>=0;j--) { if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; } return fa[x][0]; } struct node { int mx,id; int ls,rs; }t[N*60]; int tot; int rt[N]; void pushup(int x)//上传标记 //mx最多数字的个数 //id最多数字是哪一种 { if(t[x].ls&&t[x].rs)//如果有左右结点 { t[x].mx=max(t[t[x].ls].mx,t[t[x].rs].mx); t[x].id=t[t[x].ls].mx>=t[t[x].rs].mx?t[t[x].ls].id:t[t[x].rs].id; } else if(t[x].ls) { t[x].mx=t[t[x].ls].mx; t[x].id=t[t[x].ls].id; } else if(t[x].rs) { t[x].mx=t[t[x].rs].mx; t[x].id=t[t[x].rs].id; } } void upda(int &x,int l,int r,int p,int c) //upda(rt[x],1,U,z,1); //x代表结点编号,l,r代表范围 //p代表加入哪一种货物 //c代表所加的数量 { if(!x) x=++tot; if(l==r) { t[x].id=l; //在线段树中编号为x的结点,所存放食品的种类 t[x].mx+=c;//存放食品的数量 return; } if(p<=mid) //转到左子树更新 upda(t[x].ls,l,mid,p,c); else //转到右子树更新 upda(t[x].rs,mid+1,r,p,c); pushup(x); } int merge(int x,int y,int l,int r) { if(!x||!y) //哪个点不为0就返回哪个点的编号,如果同时为0就返回0 //如果此处没有返回,则说明合并的结点不为空 return x|y; if(l==r)//到了叶子点,强行合并 { t[x].mx+=t[y].mx; } else { t[x].ls=merge(t[x].ls,t[y].ls,l,mid); //左子树与左子树合并,返回得是结点的编号 t[x].rs=merge(t[x].rs,t[y].rs,mid+1,r); //右子树与右子树合并 pushup(x);//标记上传 } return x; } void sol(int x) //求出x点存放的物品,哪种编号的最多 { for(int i=hd[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa[x][0]) continue; sol(y); rt[x]=merge(rt[x],rt[y],1,U);//与其子结点进行合并 } if(t[rt[x]].mx>0) ans[x]=t[rt[x]].id; } int main() { scanf("%d%d",&n,&m);int x,y; for(int i=1;i<=n-1;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,1); dep[0]=-1; for(int j=1;j<=17;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; int z; while(m--) { scanf("%d%d%d",&x,&y,&z); int anc=lca(x,y); upda(rt[x],1,U,z,1); //对x这个端点,加1 upda(rt[y],1,U,z,1);//对y这个端点,加1 upda(rt[anc],1,U,z,-1);//对lca减1 if(fa[anc][0]) //如果lca有父亲点,也要减1 upda(rt[fa[anc][0]],1,U,z,-1); } sol(1); for(int i=1;i<=n;i++) { printf("%d\n",ans[i]); } return 0; }