POJ 3237 Tree (树链剖分)

Tree

Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 2825 Accepted: 769

Description

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 vChange the weight of the ith edge to v
NEGATE a bNegate the weight of every edge on the path from a to b
QUERY a bFind the maximum weight of edges on the path from a to b

Input

The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.

Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers ab and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.

Output

For each “QUERY” instruction, output the result on a separate line.

Sample Input

1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Sample Output

1
3

Source

POJ Monthly–2007.06.03, Lei, Tao

 

树链剖分+线段树实现

 

 

  1 /* ***********************************************
  2 Author        :kuangbin
  3 Created Time  :2013/8/17 4:04:42
  4 File Name     :F:\2013ACM练习\专题学习\数链剖分\POJ3237Tree.cpp
  5 ************************************************ */
  6 
  7 #include <stdio.h>
  8 #include <string.h>
  9 #include <iostream>
 10 #include <algorithm>
 11 #include <vector>
 12 #include <queue>
 13 #include <set>
 14 #include <map>
 15 #include <string>
 16 #include <math.h>
 17 #include <stdlib.h>
 18 #include <time.h>
 19 using namespace std;
 20 
 21 const int MAXN = 100010;
 22 struct Edge
 23 {
 24     int to,next;
 25 }edge[MAXN*2];
 26 int head[MAXN],tot;
 27 int top[MAXN];//top[v]表示v所在的重链的顶端节点
 28 int fa[MAXN]; //父亲节点
 29 int deep[MAXN];//深度
 30 int num[MAXN];//num[v]表示以v为根的子树的节点数
 31 int p[MAXN];//p[v]表示v与其父亲节点的连边在线段树中的位置
 32 int fp[MAXN];//和p数组相反
 33 int son[MAXN];//重儿子
 34 int pos;
 35 void init()
 36 {
 37     tot = 0;
 38     memset(head,-1,sizeof(head));
 39     pos = 0;
 40     memset(son,-1,sizeof(son));
 41 }
 42 void addedge(int u,int v)
 43 {
 44     edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;
 45 }
 46 void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son
 47 {
 48     deep[u] = d;
 49     fa[u] = pre;
 50     num[u] = 1;
 51     for(int i = head[u];i != -1; i = edge[i].next)
 52     {
 53         int v = edge[i].to;
 54         if(v != pre)
 55         {
 56             dfs1(v,u,d+1);
 57             num[u] += num[v];
 58             if(son[u] == -1 || num[v] > num[son[u]])
 59                 son[u] = v;
 60         }
 61     }
 62 }
 63 void getpos(int u,int sp) //第二遍dfs求出top和p
 64 {
 65     top[u] = sp;
 66     p[u] = pos++;
 67     fp[p[u]] = u;
 68     if(son[u] == -1) return;
 69     getpos(son[u],sp);
 70     for(int i = head[u] ; i != -1; i = edge[i].next)
 71     {
 72         int v = edge[i].to;
 73         if(v != son[u] && v != fa[u])
 74             getpos(v,v);
 75     }
 76 }
 77 
 78 //线段树
 79 struct Node
 80 {
 81     int l,r;
 82     int Max;
 83     int Min;
 84     int ne;
 85 }segTree[MAXN*3];
 86 void build(int i,int l,int r)
 87 {
 88     segTree[i].l = l;
 89     segTree[i].r = r;
 90     segTree[i].Max = 0;
 91     segTree[i].Min = 0;
 92     segTree[i].ne = 0;
 93     if(l == r)return;
 94     int mid = (l+r)/2;
 95     build(i<<1,l,mid);
 96     build((i<<1)|1,mid+1,r);
 97 }
 98 void push_up(int i)
 99 {
100     segTree[i].Max = max(segTree[i<<1].Max,segTree[(i<<1)|1].Max);
101     segTree[i].Min = min(segTree[i<<1].Min,segTree[(i<<1)|1].Min);
102 }
103 void push_down(int i)
104 {
105     if(segTree[i].l == segTree[i].r)return;
106     if(segTree[i].ne)
107     {
108         segTree[i<<1].Max = -segTree[i<<1].Max;
109         segTree[i<<1].Min = -segTree[i<<1].Min;
110         swap(segTree[i<<1].Min,segTree[i<<1].Max);
111         segTree[(i<<1)|1].Max = -segTree[(i<<1)|1].Max;
112         segTree[(i<<1)|1].Min = -segTree[(i<<1)|1].Min;
113         swap(segTree[(i<<1)|1].Max,segTree[(i<<1)|1].Min);
114         segTree[i<<1].ne ^= 1;
115         segTree[(i<<1)|1].ne ^= 1;
116         segTree[i].ne = 0;
117     }
118 }
119 void update(int i,int k,int val) // 更新线段树的第k个值为val
120 {
121     if(segTree[i].l == k && segTree[i].r == k)
122     {
123         segTree[i].Max = val;
124         segTree[i].Min = val;
125         segTree[i].ne = 0;
126         return;
127     }
128     push_down(i);
129     int mid = (segTree[i].l + segTree[i].r)/2;
130     if(k <= mid)update(i<<1,k,val);
131     else update((i<<1)|1,k,val);
132     push_up(i);
133 }
134 void ne_update(int i,int l,int r) // 更新线段树的区间[l,r]取反
135 {
136     if(segTree[i].l == l && segTree[i].r == r)
137     {
138         segTree[i].Max = -segTree[i].Max;
139         segTree[i].Min = -segTree[i].Min;
140         swap(segTree[i].Max,segTree[i].Min);
141         segTree[i].ne ^= 1;
142         return;
143     }
144     push_down(i);
145     int mid = (segTree[i].l + segTree[i].r)/2;
146     if(r <= mid)ne_update(i<<1,l,r);
147     else if(l > mid) ne_update((i<<1)|1,l,r);
148     else
149     {
150         ne_update(i<<1,l,mid);
151         ne_update((i<<1)|1,mid+1,r);
152     }
153     push_up(i);
154 }
155 int query(int i,int l,int r)  //查询线段树中[l,r] 的最大值
156 {
157     if(segTree[i].l == l && segTree[i].r == r)
158         return segTree[i].Max;
159     push_down(i);
160     int mid = (segTree[i].l + segTree[i].r)/2;
161     if(r <= mid)return query(i<<1,l,r);
162     else if(l > mid)return query((i<<1)|1,l,r);
163     else return max(query(i<<1,l,mid),query((i<<1)|1,mid+1,r));
164     push_up(i);
165 }
166 int findmax(int u,int v)//查询u->v边的最大值
167 {
168     int f1 = top[u], f2 = top[v];
169     int tmp = -100000000;
170     while(f1 != f2)
171     {
172         if(deep[f1] < deep[f2])
173         {
174             swap(f1,f2);
175             swap(u,v);
176         }
177         tmp = max(tmp,query(1,p[f1],p[u]));
178         u = fa[f1]; f1 = top[u];
179     }
180     if(u == v)return tmp;
181     if(deep[u] > deep[v]) swap(u,v);
182     return max(tmp,query(1,p[son[u]],p[v]));
183 }
184 void Negate(int u,int v)//把u-v路径上的边的值都设置为val
185 {
186     int f1 = top[u], f2 = top[v];
187     while(f1 != f2)
188     {
189         if(deep[f1] < deep[f2])
190         {
191             swap(f1,f2);
192             swap(u,v);
193         }
194         ne_update(1,p[f1],p[u]);
195         u = fa[f1]; f1 = top[u];
196     }
197     if(u == v)return;
198     if(deep[u] > deep[v]) swap(u,v);
199     return ne_update(1,p[son[u]],p[v]);
200 }
201 int e[MAXN][3];
202 int main()
203 {
204     //freopen("in.txt","r",stdin);
205     //freopen("out.txt","w",stdout);
206     int T;
207     int n;
208     scanf("%d",&T);
209     while(T--)
210     {
211         init();
212         scanf("%d",&n);
213         for(int i = 0;i < n-1;i++)
214         {
215             scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
216             addedge(e[i][0],e[i][1]);
217             addedge(e[i][1],e[i][0]);
218         }
219         dfs1(1,0,0);
220         getpos(1,1);
221         build(1,0,pos-1);
222         for(int i = 0;i < n-1; i++)
223         {
224             if(deep[e[i][0]] > deep[e[i][1]])
225                 swap(e[i][0],e[i][1]);
226             update(1,p[e[i][1]],e[i][2]);
227         }
228         char op[10];
229         int u,v;
230         while(scanf("%s",op) == 1)
231         {
232             if(op[0] == 'D')break;
233             scanf("%d%d",&u,&v);
234             if(op[0] == 'Q')
235                 printf("%d\n",findmax(u,v));//查询u->v路径上边权的最大值
236             else if(op[0] == 'C')
237                 update(1,p[e[u-1][1]],v);//改变第u条边的值为v
238             else Negate(u,v);
239         }
240     }
241     return 0;
242 }

 

 

 

    原文作者:kuangbin
    原文地址: https://www.cnblogs.com/kuangbin/p/3263822.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞