一棵树,初始边权和点权都为0
现在有m个操作,每一个操作:
ADD1 u v k: for nodes on the path from u to v, the value of these nodes increase by k.
ADD2 u v k: for edges on the path from u to v, the value of these edges increase by k.
操作完后,输出每一个点的点权和每一条边的边权(边权按照输入顺序输出)
我们把边权也当做点权处理
这道题本来是一道痕裸的树链剖分的题目,用树状数组维护就可以了O(nlogn*logn)
不过这样会T,因为出题人特意卡了常数
有人是加了一个输入输出外挂过的
不过这道题有更好的做法
我们在树链剖分后的数组用标记法,每次对一个连续区间+k时,我们对位置L标记+k,对位置R+1标记-k
最后从前往后加一遍就是了
O(nlogn)
注意:处理边权和点权时,对lca的处理是不同的
点权时,lca的点权也要更新
边权时,lca对应的边的边权时不需要更新的
注意2:当节点个数为1时,是没有边的,也就没有边权了,但是输出的时候我们边权这一行依然要输出,是一个空行
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<stack> #include<map> #include<set> #define LL long long #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int maxn=1e5+10; int dep[maxn]; int siz[maxn]; int chg[maxn]; int fa[maxn]; int son[maxn]; int top[maxn]; LL c[2][maxn]; int n; int e[maxn][2]; struct Edge { int to,next; }; Edge edge[maxn<<1]; int head[maxn]; int tot; void init() { memset(head,-1,sizeof head); tot=0; } void addedge(int u,int v) { edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void solve(int ); int main() { int test; int cas=1; scanf("%d",&test); while(test--){ printf("Case #%d:\n",cas++); init(); int q; scanf("%d %d",&n,&q); for(int i=1;i<n;i++){ scanf("%d %d",&e[i][0],&e[i][1]); addedge(e[i][0],e[i][1]); addedge(e[i][1],e[i][0]); } solve(q); } return 0; } void dfs0(int u,int pre) { dep[u]=dep[pre]+1; fa[u]=pre; siz[u]=1; for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].to; if(v==pre) continue; dfs0(v,u); siz[u]+=siz[v]; if(son[u]==-1 || siz[v]>siz[son[u]]) son[u]=v; } } void dfs1(int u,int tp) { top[u]=tp; chg[u]=++tot; if(son[u]==-1) return ; dfs1(son[u],tp); for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].to; if(v==fa[u] || v==son[u]) continue; dfs1(v,v); } } void update_path(int a,int b,int cnt,int k) { while(top[a]!=top[b]){ if(dep[top[a]]<dep[top[b]]) swap(a,b); c[cnt][chg[top[a]]]+=k; c[cnt][chg[a]+1]-=k; a=fa[top[a]]; } if(dep[a]<dep[b]) swap(a,b); if(cnt==1){ c[cnt][chg[b]]+=k; c[cnt][chg[a]+1]-=k; } else{ c[cnt][chg[b]+1]+=k; c[cnt][chg[a]+1]-=k; } return ; } void solve(int q) { memset(c,0,sizeof c); memset(dep,0,sizeof dep); memset(son,-1,sizeof son); dfs0(1,1); tot=0; dfs1(1,1); for(int i=1;i<=q;i++){ char str[10]; scanf("%s",str); int u,v,k; scanf("%d %d %d",&u,&v,&k); if(str[3]==‘1‘){ update_path(u,v,1,k); } else{ update_path(u,v,0,k); } } for(int i=1;i<=n;i++){ c[0][i]+=c[0][i-1]; c[1][i]+=c[1][i-1]; } for(int i=1;i<=n;i++){ printf("%d",c[1][chg[i]]); if(i<n) printf(" "); else puts(""); } for(int i=1;i<n;i++){ int cur=e[i][0]; if(dep[e[i][0]]<dep[e[i][1]]) cur=e[i][1]; printf("%d",c[0][chg[cur]]); if(i<n-1) printf(" "); } puts(""); return ; }
时间: 2024-10-25 13:31:07