題意:給一棵樹,兩種操作: 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; }