n个结点的树,两种操作:更新一条边的权值,询问两点间的路径的权值和。
典型的树链剖分。
用线段树写了,不知道为嘛TLE。先贴在这儿,待以后研究。
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> using namespace std; #define maxn 100050 #define lson i<<1,l,m #define rson i<<1|1,m+1,r struct Edge { int v,next; } edge[maxn<<1]; int tree[maxn],tot,cnt,a,b,e[maxn][3],head[maxn], dep[maxn], id[maxn], fa[maxn], top[maxn], son[maxn], num[maxn]; void add(int a, int b) { edge[++cnt].v = b; edge[cnt].next = head[a]; head[a] = cnt; } void dfs(int v) { num[v] = 1,son[v] = 0; for (int i = head[v]; i > 0; i = edge[i].next) if (edge[i].v != fa[v]) { fa[edge[i].v] = v; dep[edge[i].v] = dep[v]+1; dfs(edge[i].v); if (num[edge[i].v] > num[son[v]]) son[v] = edge[i].v; num[v] += num[edge[i].v]; } } void dfs2(int v, int tp) { id[v] = tot++; top[v] = tp; if (son[v] != 0) dfs2(son[v], top[v]); for (int i = head[v]; i > 0; i = edge[i].next) if (edge[i].v != son[v] && edge[i].v != fa[v]) dfs2(edge[i].v, edge[i].v); } void update(int i, int l, int r, int k, int x) { if (l == r) { tree[i] = x; return;} int m = (l + r)>>1; if(k<=m) update(lson,k,x); else update(rson,k,x); tree[i] = tree[i<<1]+tree[i<<1|1]; } int query(int i, int l, int r, int L, int R) { if (L<= l && r <= R) return tree[i]; int m = (l + r)>>1,ans=0; if(L<=m) ans+=query(lson,L,R); if(R>m) ans+=query(rson,L,R); return ans; } int find(int va, int vb) { int f1 = top[va], f2 = top[vb], tmp = 0; while (f1 != f2) { if (dep[f1] < dep[f2]) { swap(f1, f2); swap(va, vb); } tmp+=query(1, 1, tot, id[f1], id[va]); va = fa[f1]; f1 = top[va]; } if (va == vb) return tmp; if (dep[va] > dep[vb]) swap(va, vb); tmp+=query(1, 1, tot, id[son[va]], id[vb]); return tmp; } int main() { int q,s,n; scanf("%d%d%d", &n,&q,&s); fa[1] = tot = dep[1] = cnt = 0; memset(num, 0, sizeof(num)); memset(head, 0, sizeof(head)); memset(tree, 0, sizeof(tree)); for (int i = 1; i < n; i++) { scanf("%d%d%d", &e[i][0], &e[i][1], &e[i][2]); add(e[i][0],e[i][1]); add(e[i][1],e[i][0]); } dfs(1); dfs2(1,1); for (int i = 1; i < n; i++) { if (dep[e[i][0]] > dep[e[i][1]]) swap(e[i][0], e[i][1]); update(1, 1, tot, id[e[i][1]], e[i][2]); } while(q--) { int c; scanf("%d",&c); if(c) { scanf("%d%d",&a,&b); update(1,1,tot,id[e[a][1]],b); } else { scanf("%d",&a); printf("%d\n",find(s,a)); s=a; } } return 0; }
后面改用树状数组写了:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100005 #define low(x) ((x)&-(x)) int n,q,s,head[N],e[N<<1],next[N<<1],tot,fa[N],num[N],son[N],dep[N],c[N],pos[N],top[N],ID[N],w[N],t; void add(int u,int v) { e[++tot]=v; next[tot]=head[u]; head[u]=tot; } void dfs(int u) { num[u]=1,son[u]=0; for(int i=head[u];i;i=next[i]) { int v=e[i]; if(v!=fa[u]) { fa[v]=u,dep[v]=dep[u]+1; dfs(v); num[u]+=num[v]; if(num[son[u]]<num[v]) son[u]=v; } } } void dfs2(int u,int tp) { pos[u]=t++,top[u]=tp; if(son[u]) dfs2(son[u],tp); for(int i=head[u];i;i=next[i]) { int v=e[i]; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); ID[(i+1)/2]=pos[v]; } } void update(int x,int d) { for(;x<=n;x+=low(x)) c[x]+=d; } int sum(int x) { int ans=0; for(;x>0;x-=low(x)) ans+=c[x]; return ans; } int query(int a,int b) { int f1=top[a],f2=top[b],ans=0; while(f1!=f2) { if(dep[f1]<dep[f2]) { swap(a,b); swap(f1,f2); } ans+=sum(pos[a])-sum(pos[f1]-1); a=fa[f1]; f1=top[a]; } if(a!=b) { if(dep[a]>dep[b]) swap(a,b); ans+=sum(pos[b])-sum(pos[a]); } return ans; } int main() { scanf("%d%d%d",&n,&q,&s); for(int i=1,u,v;i<n;i++) { scanf("%d%d%d",&u,&v,&w[i]); add(u,v); add(v,u); } dfs(1),dfs2(1,1); for(int i=1;i<n;i++) update(ID[i],w[i]); while(q--) { int op,x,y; scanf("%d",&op); if(op) { scanf("%d%d",&x,&y); update(ID[x],y-w[x]); w[x]=y; } else { scanf("%d",&x); printf("%d\n",query(s,x)); s=x; } } return 0; }