题意:给定一棵含n个结点的树,共有q次操作,分为两种
0 c :求从位置s到c的距离,然后s变成c
1 a b:把第a条边的权值变为b
n<10w,q<10w
题解:求树中两点距离显然是LCA,关于对原树中边权的修改,假设改了(a,b)使得其边增大了c,那么如果a是b的父亲,那么以b为子树的所有结点到根的距离都将增加c。求解LCA可以得到dfs序列,记录下每个结点初始访问时间以及最后访问时间,那么如果以该节点为子树的结点距根节点距离有变,只需对这个区间内每个值加上c即可,线段树可以做,但太麻烦了,实际上可以用树状数组直接在这区间头加上c,区间尾后面减去c,然后求值时受影响的就只有这个区间了。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N = 400005; // 1<<20; int prt[N],pnt[N], next[N], head[N],cost[N]; // 邻接表 bool visited[N]; // 初始为0,从根遍历 int e,id; int dep[N], E[N], R[N],ED[N],fa[N],dist[N]; // dep:dfs遍历节点深度, E:dfs序列, R:第一次被遍历的下标 void DFS(int u, int d); int d[40], st[N][40]; int ar[N]; // index: 1 ~ N int lowb(int t) { return t&(-t) ; } void add(int i, int v) { for ( ; i < N; ar[i] += v, i += lowb(i)); } int sum(int i) { int s = 0; for ( ; i > 0; s += ar[i], i -= lowb(i)); return s; } int Query(int x, int y) { int k; k = int( log(double(y-x+1))/log(2.0) ); return dep[ st[x][k] ] > dep[ st[y-d[k]+1][k] ] ? st[y-d[k]+1][k] : st[x][k]; } int LCA(int x,int y) { if( x > y ) swap(x,y); return E[Query(x, y)]; } void DFS(int u, int d,int dis) { visited[u] = 1; R[u] = id; E[id] = u; dist[u]=dis; dep[id++] = d; for( int i=head[u]; i != -1; i=next[i] ) if( visited[ pnt[i] ] == 0 ) { fa[pnt[i]]=u; DFS(pnt[i], d+1,cost[i]+dis); E[id] = u; dep[id++] = d; } ED[u]=id; } void InitRMQ() { int i, j; for( d[0]=1, i=1; i < 20; ++i ) d[i] = 2*d[i-1]; for( i=0; i < id; ++i ) st[i][0] = i; int k = int( log(double(N))/log(2.0) ) + 1; for( j=1; j < k; ++j ) for( i=0; i < id; ++i ) if( i+d[j-1]-1 < id ) st[i][j]=dep[st[i][j-1]]>dep[ st[i+d[j-1]][j-1]]?st[i+d[j-1]][j-1]:st[i][j-1]; else break; } void addedge(int a,int b,int c) { prt[e]=a;pnt[e]=b;next[e]=head[a];cost[e]=c;head[a]=e++; prt[e]=b;pnt[e]=a;next[e]=head[b];cost[e]=c;head[b]=e++; } struct Edge { int a,b,c; Edge(){} Edge(int _a,int _b,int _c) { a=_a,b=_b,c=_c; } }EE[N]; int main() { int n,q,s,a,b,c,op,x,y,z; while(scanf("%d%d%d",&n,&q,&s)!=EOF) { memset(head,-1,sizeof(head)); memset(ar,0,sizeof(ar)); memset(visited,0,sizeof(visited)); id=e=0; for(int i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); EE[i]=Edge(a,b,c); addedge(a,b,c); } DFS(s,0,0); fa[s]=s; InitRMQ(); for(int i=0;i<q;i++) { scanf("%d",&op); if(op==0) { scanf("%d",&b); x=R[s];y=R[b];z=R[c=LCA(x,y)]; printf("%d\n",sum(x+1)+sum(y+1)-2*sum(z+1)+dist[s]+dist[b]-2*dist[c]); s=b; } else { scanf("%d%d",&a,&c); x=EE[a].a; y=EE[a].b; int tp=c-EE[a].c; EE[a].c=c; if(fa[x]==y) swap(x,y); add(R[y]+1,tp); add(ED[y]+1,-tp); } } } return 0; }