poj 3237 Tree 树链剖分

题目链接: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 }
原文地址:https://www.cnblogs.com/huangxf/p/4345123.html