2 4 2 1 2 2 3 2 4 ADD1 1 4 1 ADD2 3 4 2 4 2 1 2 2 3 1 4 ADD1 1 4 5 ADD2 3 2 4
Case #1: 1 1 0 1 0 2 2 Case #2: 5 0 0 5 0 4 0
之前也就做了一道类似LCA的题,对LCA还不是很熟悉,比赛的时候感觉是LCA但是不会写。
看了题解,仔细想想这题其实真不难。。就是记录每个操作,最后从叶子到根网上遍历一遍,每次把要修改的值传上去就行了。。
对点u,v加w就是:add1[u]+=w,add1[v]+=w,x=lca(u,v),add[x]-=w(因为传上来两个w),因为到了x之后不能再往上传,设sub[x]+=x,每个点的add值减去sub值就是要往上传的值。
设add2[u]为u和fa[u]的边要增加的值,那么对边操作add2[u]+=w,add2[v]+=w,add2[x]-=2*w。
因为这题要按输入的顺序输出边的权值,那么还要记录u和u的父节点之间的边的编号。
注意要输入输出外挂才能过。。。。。。。
#include<iostream> #include<algorithm> #include<queue> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<set> #include<map> #include<stack> #define INF 0x3f3f3f3f #define MAXN 100010 #define LOGMAXN 20 #define MAXM 1500 #define MOD 1000000007 #define MAXNODE 8*MAXN #define eps 1e-10 #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; int T,N,M,L[MAXN],anc[MAXN][LOGMAXN],fa[MAXN],e[MAXN],deg[MAXN]; LL add1[MAXN],add2[MAXN],sub[MAXN],node[MAXN],edge[MAXN]; char str[10]; struct Edge{ int to,id; Edge(){} Edge(int to,int id):to(to),id(id){} }; vector<Edge> G[MAXN]; void DFS(int u,int f,int level){ L[u]=level; int len=G[u].size(); for(int i=0;i<len;i++){ int v=G[u][i].to; if(v!=f){ deg[u]++; fa[v]=u; e[v]=G[u][i].id; DFS(v,u,level+1); } } } void lca_init(){ for(int i=1;i<=N;i++){ anc[i][0]=fa[i]; for(int j=1;(1<<j)<=N;j++) anc[i][j]=-1; } for(int j=1;(1<<j)<=N;j++) for(int i=1;i<=N;i++) if(anc[i][j-1]!=-1){ int a=anc[i][j-1]; anc[i][j]=anc[a][j-1]; } } int lca(int p,int q){ if(L[p]<L[q]) swap(p,q); int log; for(log=0;(1<<log)<=L[p];log++); log--; for(int i=log;i>=0;i--) if(L[p]-(1<<i)>=L[q]) p=anc[p][i]; if(p==q) return p; for(int i=log;i>=0;i--) if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){ p=anc[p][i]; q=anc[q][i]; } return fa[p]; } void solve(){ queue<int> q; for(int i=1;i<=N;i++) if(!deg[i]) q.push(i); //叶子节点 while(!q.empty()){ int x=q.front(); q.pop(); node[x]=add1[x]; add1[x]-=sub[x]; edge[e[x]]=add2[x]; int f=fa[x]; add1[f]+=add1[x]; add2[f]+=add2[x]; if(!(--deg[f])) q.push(f); //子节点都处理完了,成为叶子节点 } } template <class T> inline bool scan_d(T &ret) { char c; int sgn; if(c=getchar(),c==EOF) return 0; //EOF while(c!='-'&&(c<'0'||c>'9')) c=getchar(); sgn=(c=='-')?-1:1; ret=(c=='-')?0:(c-'0'); while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0'); ret*=sgn; return 1; } inline void out(long long x) { if(x>9) out(x/10); putchar(x%10+'0'); } int main(){ freopen("in.txt","r",stdin); int cas=0; scan_d(T); while(T--){ scan_d(N); scan_d(M); for(int i=1;i<=N;i++) G[i].clear(); int u,v; for(int i=1;i<=N-1;i++){ scan_d(u); scan_d(v); G[u].push_back(Edge(v,i)); G[v].push_back(Edge(u,i)); } memset(fa,0,sizeof(fa)); memset(deg,0,sizeof(deg)); DFS(1,-1,0); lca_init(); memset(add1,0,sizeof(add1)); memset(add2,0,sizeof(add2)); memset(sub,0,sizeof(sub)); while(M--){ int u,v,w; scanf("%s",str); scan_d(u); scan_d(v); scan_d(w); int x=lca(u,v); if(str[3]=='1'){ add1[u]+=w; add1[v]+=w; add1[x]-=w; sub[x]+=w; } else{ add2[u]+=w; add2[v]+=w; add2[x]-=w*2; } } solve(); printf("Case #%d:\n",++cas); for(int i=1;i<=N;i++){ if(i>1) printf(" "); out(node[i]); } puts(""); if(N==1) puts(""); else{ for(int i=1;i<=N-1;i++){ if(i>1) printf(" "); out(edge[i]); } puts(""); } } return 0; }