标签:多个 比较 ret code 两种 链式前向星 ems init amp
题意:
给出一棵树,两种操作:
1.求出a到b的距离;
2.修改某一条边的权值。
思路:
可以用树链刨分(我不会
首先,求a到b的距离,因为有很多组询问,所以必须得用lca解决
ans = dis[a] + dis[b] - 2 * dis[lca(a,b)] dis是这个点到根的距离
修改某一条边的权值这里比较麻烦,因为修改了某一条边的权值之后,可能有很多个点的距离都会被影响,但是暴力修改的话,会tle
所以就想到用dfs序处理,每一个点的dfs序的区间控制这个点以及它的子树上的所有点
当某一条边被修改时,那么这条边所连接的时间戳比较大的点及其它的子树的所有点的这个区间都会被影响,那么就直接修改区间
查询的时候,只需要查询3个点,a , b , lca(a,b),所以这就是树状数组的区间修改,单点查询,不懂话欢迎看我的算法学习中的这部分??
poj毒瘤,所以只能用链式前向星
边数是点数 * 2,又因为这个错误re了无数发??
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 const int N = 1e5 + 10; 7 struct edge 8 { 9 int v,cost,next; 10 }e[N * 2]; 11 int n,q,s; 12 int node[N][3]; 13 int par[N],st[N],en[N],anc[N][30],sum[N],dep[N],head[N]; 14 int clk,cnt; 15 int c[N]; 16 17 void adde(int u,int v,int cost) 18 { 19 e[cnt].v = v; 20 e[cnt].cost = cost; 21 e[cnt].next = head[u]; 22 head[u] = cnt++; 23 } 24 25 int lowbit(int x) 26 { 27 return x&(-x); 28 } 29 30 void add(int x,int k) 31 { 32 for (int i = x;i <= n;i += lowbit(i)) c[i] += k; 33 } 34 35 int getsum(int x) 36 { 37 int ans = 0; 38 for (int i = x;i > 0;i -= lowbit(i)) ans += c[i]; 39 return ans; 40 } 41 42 void dfs(int u,int fa,int dis) 43 { 44 sum[u] = dis; 45 st[u] = ++clk; 46 par[u] = fa; 47 dep[u] = dep[fa] + 1; 48 for (int i = head[u];i;i = e[i].next) 49 { 50 edge E = e[i]; 51 int v = E.v; 52 if (v != fa) 53 { 54 dfs(v,u,sum[u] + E.cost); 55 } 56 } 57 en[u] = clk; 58 } 59 60 void pred(void) 61 { 62 dfs(1,0,0); 63 for (int i = 1;i <= n;i++) anc[i][0] = par[i]; 64 for (int j = 1;j <= 25;j++) 65 { 66 for (int i = 1;i <= n;i++) 67 { 68 anc[i][j] = anc[anc[i][j-1]][j-1]; 69 } 70 } 71 } 72 73 int lca(int x,int y) 74 { 75 if (dep[x] < dep[y]) swap(x,y); 76 int k = dep[x] - dep[y]; 77 for (int i = 0;i <= 25;i++) 78 { 79 if (k >> i & 1) x = anc[x][i]; 80 } 81 if (x == y) return x; 82 for (int i = 25;i >= 0;i--) 83 { 84 if (anc[x][i] != anc[y][i]) 85 { 86 x = anc[x][i]; 87 y = anc[y][i]; 88 } 89 } 90 return par[x]; 91 } 92 93 void init(void) 94 { 95 memset(par,0,sizeof(par)); 96 memset(en,0,sizeof(en)); 97 memset(st,0,sizeof(st)); 98 memset(anc,0,sizeof(anc)); 99 memset(c,0,sizeof(c)); 100 memset(sum,0,sizeof(sum)); 101 memset(dep,0,sizeof(dep)); 102 memset(head,0,sizeof(head)); 103 memset(e,0,sizeof(e)); 104 clk = 0; 105 cnt = 1; 106 107 } 108 109 int main() 110 { 111 while (~scanf("%d%d%d",&n,&q,&s)) 112 { 113 init(); 114 for (int i = 0;i < n - 1;i++) 115 { 116 int x,y,z; 117 scanf("%d%d%d",&x,&y,&z); 118 adde(x,y,z); 119 adde(y,x,z); 120 node[i][0] = x; 121 node[i][1] = y; 122 node[i][2] = z; 123 } 124 pred(); 125 while (q--) 126 { 127 int op; 128 scanf("%d",&op); 129 if (op == 0) 130 { 131 int u; 132 scanf("%d",&u); 133 int js = lca(s,u); 134 int ans = sum[s] + sum[u] - 2 * sum[js]; 135 int tmp = getsum(st[s]) + getsum(st[u]) - getsum(st[js]) * 2; 136 printf("%d\n",ans + tmp); 137 s = u; 138 } 139 else 140 { 141 int id,w; 142 scanf("%d%d",&id,&w); 143 id--; 144 int ch = w - node[id][2]; 145 node[id][2] = w; 146 int x = node[id][0],y = node[id][1]; 147 if (st[x] < st[y]) x = y; 148 int l = st[x],r = en[x]; 149 add(l,ch); 150 add(r+1,-ch); 151 } 152 } 153 } 154 return 0; 155 }
标签:多个 比较 ret code 两种 链式前向星 ems init amp
原文地址:https://www.cnblogs.com/kickit/p/9173022.html