题意:给一棵树,两种操作: ADD1: 给u-v路径上所有点加上值k, ADD2:给u-v路径上所有边加上k,初始值都为0,问最后每个点和每条边的值,输出。
解法:树链剖分可做,剖出来如果直接用线段树来区间更新的话会TLE,所以要换一种姿势,有一种树链剖分的经典姿势就是看做树状数组一样,每次加值的时候,比如u->v之间加一个值k,那么在u处+k,v+1处-k即可,然后扫一遍,每次把当前位置要做的操作做完,此时总共加的值就是当前处的值,扫一遍的时候维护的是前缀的和,也就是两个ans不清零。
这题卡时间太紧,不加读入挂会T,不加输出挂的话跑4921ms,也是飘过,加了输入输出挂才稍微好点,4687ms,可能是树链剖分不够优越
代码:
#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define lll __int64 using namespace std; #define N 100007 int siz[N]; //子树大小 int son[N]; //重儿子 int dep[N]; //深度 int pos[N],apos[N]; //点在线段树中的位置 int Top[N]; //所在重链的祖先 int fa[N]; //父节点 lll eans[N],nans[N]; //答案 int head[2*N],tot,POS,n,m; struct Edge { int v,next; }G[2*N],Qe[10*N],Qn[10*N]; int heade[10*N],headn[10*N],tote,totn; struct node { int u,v; }edge[N]; void init() { POS = tot = tote = totn = 0; memset(head,-1,sizeof(head)); memset(son,-1,sizeof(son)); memset(heade,-1,sizeof(heade)); memset(headn,-1,sizeof(headn)); } void addedge(int u,int v) { G[tot].v = v, G[tot].next = head[u], head[u] = tot++; G[tot].v = u, G[tot].next = head[v], head[v] = tot++; } void ADDNedge(int u,int v) //代替vector来存操作 { Qn[totn].v = v, Qn[totn].next = headn[u], headn[u] = totn++; } void ADDEedge(int u,int v) //代替vector来存操作 { Qe[tote].v = v, Qe[tote].next = heade[u], heade[u] = tote++; } void dfs(int u,int f) { dep[u] = dep[f]+1; siz[u] = 1; for(int i=head[u];i!=-1;i=G[i].next) { int v = G[i].v; if(v == f) continue; fa[v] = u; dfs(v,u); if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v; siz[u] += siz[v]; } } void dfs2(int u,int top) { pos[u] = ++POS; apos[POS] = u; Top[u] = top; if(son[u] != -1) dfs2(son[u],top); for(int i=head[u];i!=-1;i=G[i].next) { int v = G[i].v; if(v != fa[u] && v != son[u]) dfs2(v,v); } } void AddEdge(int u,int v,int k) { int fx = Top[u], fy = Top[v]; while(fx != fy) { if(dep[fx] < dep[fy]) { swap(u,v); swap(fx,fy); } ADDEedge(pos[fx],k); ADDEedge(pos[u]+1,-k); u = fa[fx]; fx = Top[u]; } if(dep[u] > dep[v]) swap(u,v); ADDEedge(pos[son[u]],k); ADDEedge(pos[v]+1,-k); } void AddNode(int u,int v,int k) { int fx = Top[u], fy = Top[v]; while(fx != fy) { if(dep[fx] < dep[fy]) { swap(u,v); swap(fx,fy); } ADDNedge(pos[fx],k); ADDNedge(pos[u]+1,-k); u = fa[fx]; fx = Top[u]; } if(dep[u] > dep[v]) swap(u,v); ADDNedge(pos[u],k); ADDNedge(pos[v]+1,-k); } inline int in() { char ch; int a = 0; while((ch = getchar()) == ' ' || ch == '\n'); a += ch - '0'; while((ch = getchar()) != ' ' && ch != '\n') { a *= 10; a += ch - '0'; } return a; } inline void out(lll num){ bool flag=false; if(num<0){ putchar('-'); num=-num; } int ans[22],top=0; while(num!=0){ ans[top++]=num%10; num/=10; } if(top==0) putchar('0'); for(int i=top-1;i>=0;i--){ char ch=ans[i]+'0'; putchar(ch); } } int main() { int u,v,k,i,j,t,cs = 1; char ss[10]; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); init(); for(i=1;i<n;i++) { edge[i].u = in(); edge[i].v = in(); addedge(edge[i].u,edge[i].v); } dep[0] = 0; dfs(1,0); dfs2(1,1); while(m--) { scanf("%s",ss); u = in(), v = in(), k = in(); if(ss[3] == '1') //node AddNode(u,v,k); else AddEdge(u,v,k); } printf("Case #%d:\n",cs++); lll ansedge = 0,ansnode = 0; for(i=1;i<=n;i++) { for(j=headn[i];j!=-1;j=Qn[j].next) ansnode += Qn[j].v; for(j=heade[i];j!=-1;j=Qe[j].next) ansedge += Qe[j].v; nans[apos[i]] = ansnode; eans[apos[i]] = ansedge; } for(i=1;i<=n;i++) { out(nans[i]); printf("%c",i==n?'\n':' '); } for(i=1;i<n;i++) { int u = edge[i].u, v = edge[i].v; if(dep[u] > dep[v]) swap(u,v); out(eans[v]); printf("%c",i==n-1?'\n':' '); } if(n == 1) puts(""); //PE.. } return 0; }