题意:一棵树,给你很多对点以及一个值,在这两点路径上的点的值增加那么多,问最后所有点的值。
思路:对于两个点,找他们的最近刚刚祖先,然后他们到最近公共祖先的路径上的所有点值增加,这里离线处理,并查集时注意不能压缩路径。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; int m,n; int fst[105555],next[211111],node[211111],en; bool vis[105555]; int ans[105555]; int f[105555]; int t; struct qq { int v; int val; }; vector<qq>d[105555]; vector<qq>g[105555]; void init() { en=0; memset(fst,-1,sizeof(fst)); memset(vis,0,sizeof(vis)); memset(ans,0,sizeof(ans)); for(int i=0;i<n;i++) { g[i].clear(); d[i].clear(); f[i]=i; } } void add(int u,int v) { next[en]=fst[u]; fst[u]=en; node[en]=v; en++; } int find(int x) { if(f[x]==x)return x; else return find(f[x]); } void ad(int v,int r,int va) { if(v==r)return; ans[v]+=va; ad(f[v],r,va); } void tarjan(int u,int r) { for(int i=fst[u];i!=-1;i=next[i]) { int v=node[i]; if(v!=r)tarjan(v,u); } int size=g[u].size(); for(int i=0;i<size;i++) { qq te=g[u][i]; if(vis[te.v]) { int rot=find(te.v); ad(te.v,rot,te.val); ans[rot]+=te.val; qq tte; tte.v=u; tte.val=te.val; d[rot].push_back(tte); } } f[u]=r; vis[u]=1; int ss=d[u].size(); for(int i=0;i<ss;i++) { qq te=d[u][i]; ad(te.v,u,te.val); } } int main() { int ca=1; int u,v,va; scanf("%d",&t); while(t--) { scanf("%d",&n); init(); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } scanf("%d",&m); for(int i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&va); if(u==v) { ans[u]+=va; continue; } qq te; te.v=u; te.val=va; g[v].push_back(te); te.v=v; g[u].push_back(te); } tarjan(0,0); cout<<"Case #"<<ca++<<":"<<endl; for(int i=0;i<n;i++)cout<<ans[i]<<endl; } return 0; }