题目链接:http://poj.org/problem?id=3237
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGE i v |
Change the weight of the ith edge to v |
NEGATE a b |
Negate the weight of every edge on the path from a to b |
QUERY a b |
Find the maximum weight of edges on the path from a to b |
题意描述:一棵树有n个节点和n-1条边,每条边有一个权值。现在给出三种操作:
CHANGE I V:把第i条边的值改为v
NEGATE A B:把A到B的路径上的所有边的值取反(正为负,负改为正)
QUERY A B:询问A到B的路径上的边权值的最大值。
算法分析:树链剖分解决。把边权值移到节点上面,由于操作上有对值取反,所有我们不止要运用线段树统计区间最大值maxnum,还要统计区间最小值minnum,这样在取反操作后,maxnum=-maxnum,minnum=-minnum,再把两个值交换:swap(maxnum,minnum)即可。
说明:阅读了一些大牛的代码,感觉线段树部分还是结构体比数组方便一些,树链剖分刚开始学,代码和解题思想很多是借鉴大牛们的,只是把代码风格改成自己的了,相信只有不断学习和解题才会对树链剖分有一定理解的。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<vector> 8 #define inf 0x7fffffff 9 using namespace std; 10 const int maxn=100000+10; 11 12 struct Edge 13 { 14 int to,next; 15 }edge[maxn*2]; 16 int head[maxn],edgenum; 17 int top[maxn];//top[v]表示v所在的重链的顶端节点 18 int fa[maxn]; //父亲节点 19 int dep[maxn];//深度 20 int siz[maxn];//siz[v]表示以v为根的子树的节点数 21 int tid[maxn];//tid[v]表示v与其父亲节点的连边在线段树中的位置 22 int tid2[maxn];//和tid数组相反 23 int son[maxn];//重儿子 24 int pos; 25 void init() 26 { 27 edgenum=0; 28 memset(head,-1,sizeof(head)); 29 pos=0; 30 memset(son,-1,sizeof(son)); 31 } 32 void addedge(int u,int v) 33 { 34 edge[edgenum].to=v ;edge[edgenum].next=head[u]; 35 head[u]=edgenum++; 36 37 edge[edgenum].to=u ;edge[edgenum].next=head[v]; 38 head[v]=edgenum++; 39 } 40 41 void dfs1(int u,int pre,int d) //第一遍dfs求出fa,dep,siz,son 42 { 43 dep[u]=d; 44 fa[u]=pre; 45 siz[u]=1; 46 for (int i=head[u] ;i != -1 ;i=edge[i].next) 47 { 48 int v=edge[i].to; 49 if (v != pre) 50 { 51 dfs1(v,u,d+1); 52 siz[u] += siz[v]; 53 if (son[u] == -1 || siz[v]>siz[son[u]]) 54 son[u]=v; 55 } 56 } 57 } 58 void dfs2(int u,int tp) //第二遍dfs求出top和tid 59 { 60 top[u]=tp; 61 tid[u]= ++pos; 62 tid2[pos]=u; 63 if (son[u] == -1) return; 64 dfs2(son[u],tp); 65 for (int i=head[u] ;i != -1 ;i=edge[i].next) 66 { 67 int v=edge[i].to; 68 if (v != son[u] && v != fa[u]) 69 dfs2(v,v); 70 } 71 } 72 73 //线段树 74 struct node 75 { 76 int l,r; 77 int Max; 78 int Min; 79 int ne; 80 }segTree[maxn*3]; 81 82 void build(int l,int r,int rt) 83 { 84 segTree[rt].l=l; 85 segTree[rt].r=r; 86 segTree[rt].Max=0; 87 segTree[rt].Min=0; 88 segTree[rt].ne=0; 89 if (l==r) return ; 90 int mid=(l+r)/2; 91 build(l,mid,rt<<1); 92 build(mid+1,r,rt<<1|1); 93 } 94 void PushUP(int rt) 95 { 96 segTree[rt].Max = max(segTree[rt<<1].Max,segTree[rt<<1|1].Max); 97 segTree[rt].Min = min(segTree[rt<<1].Min,segTree[rt<<1|1].Min); 98 } 99 void PushDown(int rt) 100 { 101 if (segTree[rt].l == segTree[rt].r) return ; 102 if (segTree[rt].ne) 103 { 104 segTree[rt<<1].Max = -segTree[rt<<1].Max; 105 segTree[rt<<1].Min = -segTree[rt<<1].Min; 106 swap(segTree[rt<<1].Min,segTree[rt<<1].Max); 107 segTree[rt<<1|1].Max = -segTree[rt<<1|1].Max; 108 segTree[rt<<1|1].Min = -segTree[rt<<1|1].Min; 109 swap(segTree[rt<<1|1].Max,segTree[rt<<1|1].Min); 110 segTree[rt<<1].ne ^= 1; 111 segTree[rt<<1|1].ne ^= 1; 112 segTree[rt].ne = 0; 113 } 114 } 115 116 void update(int k,int val,int rt) // 更新线段树的第k个值为val 117 { 118 if(segTree[rt].l == k && segTree[rt].r == k) 119 { 120 segTree[rt].Max = val; 121 segTree[rt].Min = val; 122 segTree[rt].ne = 0; 123 return; 124 } 125 PushDown(rt); 126 int mid = (segTree[rt].l + segTree[rt].r)/2; 127 if(k <= mid)update(k,val,rt<<1); 128 else update(k,val,(rt<<1)|1); 129 PushUP(rt); 130 } 131 void ne_update(int l,int r,int rt) // 更新线段树的区间[l,r]取反 132 { 133 if (segTree[rt].l == l && segTree[rt].r == r) 134 { 135 segTree[rt].Max = -segTree[rt].Max; 136 segTree[rt].Min = -segTree[rt].Min; 137 swap(segTree[rt].Max,segTree[rt].Min); 138 segTree[rt].ne ^= 1; 139 return; 140 } 141 PushDown(rt); 142 int mid = (segTree[rt].l + segTree[rt].r)/2; 143 if (r <= mid) ne_update(l,r,rt<<1); 144 else if (l > mid) ne_update(l,r,(rt<<1)|1); 145 else 146 { 147 ne_update(l,mid,rt<<1); 148 ne_update(mid+1,r,(rt<<1)|1); 149 } 150 PushUP(rt); 151 } 152 int query(int l,int r,int rt) //查询线段树中[l,r] 的最大值 153 { 154 if (segTree[rt].l == l && segTree[rt].r == r) 155 return segTree[rt].Max; 156 PushDown(rt); 157 int mid = (segTree[rt].l+segTree[rt].r)>>1; 158 if (r <= mid) return query(l,r,rt<<1); 159 else if (l > mid) return query(l,r,(rt<<1)|1); 160 else return max(query(l,mid,rt<<1),query(mid+1,r,(rt<<1)|1)); 161 PushUP(rt); 162 } 163 int findmax(int u,int v)//查询u->v边的最大值 164 { 165 int f1 = top[u], f2 = top[v]; 166 int tmp = -100000000; 167 while(f1 != f2) 168 { 169 if(dep[f1] < dep[f2]) 170 { 171 swap(f1,f2); 172 swap(u,v); 173 } 174 tmp = max(tmp,query(tid[f1],tid[u],1)); 175 u = fa[f1]; f1 = top[u]; 176 } 177 if(u == v)return tmp; 178 if(dep[u] > dep[v]) swap(u,v); 179 return max(tmp,query(tid[son[u]],tid[v],1)); 180 } 181 182 void Negate(int u,int v) 183 { 184 int f1=top[u],f2=top[v]; 185 while (f1 != f2) 186 { 187 if (dep[f1]<dep[f2]) 188 { 189 swap(f1,f2); 190 swap(u,v); 191 } 192 ne_update(tid[f1],tid[u],1); 193 u=fa[f1] ;f1=top[u]; 194 } 195 if (u==v) return; 196 if (dep[u]>dep[v]) swap(u,v); 197 return ne_update(tid[son[u] ],tid[v],1); 198 } 199 200 int e[maxn][3]; 201 int main() 202 { 203 int T; 204 int n; 205 scanf("%d",&T); 206 while(T--) 207 { 208 init(); 209 scanf("%d",&n); 210 for(int i = 0;i < n-1;i++) 211 { 212 scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); 213 addedge(e[i][0],e[i][1]); 214 } 215 dfs1(1,0,0); 216 dfs2(1,1); 217 build(1,n,1); 218 for (int i = 0;i < n-1; i++) 219 { 220 if (dep[e[i][0]]>dep[e[i][1]]) 221 swap(e[i][0],e[i][1]); 222 update(tid[e[i][1]],e[i][2],1); 223 } 224 char op[10]; 225 int u,v; 226 while (scanf("%s",op) == 1) 227 { 228 if (op[0] == 'D') break; 229 scanf("%d%d",&u,&v); 230 if (op[0]=='Q') 231 printf("%d ",findmax(u,v));//查询u->v路径上边权的最大值 232 else if (op[0]=='C') 233 update(tid[e[u-1][1]],v,1);//改变第u条边的值为v 234 else Negate(u,v); 235 } 236 } 237 return 0; 238 }