zoukankan      html  css  js  c++  java
• POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘

 Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12247 Accepted: 3151

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 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

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

题意就是： 有T组数据 ，给你n个点的树，有三种操作：

1.CHANGE i v :将第i条边的值改为v

2.NEGATE a b :将a点到b点路径上的边权取反

3.QUERY a b :查询a点到b点路径上最大的边权值，

由于有取反操作，记录最大和最小值 然后取反并交换就可以，用线段树来维护，真香警告。。。

代码:

```  1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<bitset>
6 #include<cassert>
7 #include<cctype>
8 #include<cmath>
9 #include<cstdlib>
10 #include<ctime>
11 #include<deque>
12 #include<iomanip>
13 #include<list>
14 #include<map>
15 #include<queue>
16 #include<set>
17 #include<stack>
18 #include<vector>
19 using namespace std;
20 typedef long long ll;
21
22 const double PI=acos(-1.0);
23 const double eps=1e-6;
24 const ll mod=1e9+7;
25 const int inf=0x3f3f3f3f;
26 const int maxn=1e4+10;
27 const int maxm=100+10;
28 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
29 #define lson l,m,rt<<1
30 #define rson m+1,r,rt<<1|1
31
33
34 struct Edge{
35     int to,next;
36 }edge[maxn<<1];
37
39 {
40     edge[cnt].to=v;
43 }
44
45 int val[maxn],siz[maxn],dep[maxn],son[maxn];
46 int top[maxn],tid[maxn],pos[maxn],fa[maxn];
47
48 void init()//初始化
49 {
51     memset(son,-1,sizeof(son));
52     cnt=num=0;
53 }
54
55 ///树链剖分部分
56 void dfs1(int u,int father)//第一遍dfs，可以得到当前节点的父亲节点，当前节点的深度，当前节点的重儿子
57 {
58     //更新dep，fa，siz数组
59     siz[u]=1;//保存以u为根的子树节点个数
60     fa[u]=father;//保存爸爸
61     dep[u]=dep[father]+1;//记录深度
63         int v=edge[i].to;
64         if(v!=father){//如果连接的是当前节点的父亲节点，则不处理
65             dfs1(v,u);
66             siz[u]+=siz[v];//直接子树节点相加，当前节点的size加上子节点的size
67             if(son[u]==-1||siz[v]>siz[son[u]])//如果没有设置过重节点son或者子节点v的size大于之前记录的重节点son，进行更新
68                 son[u]=v;//保存重儿子
69         }
70     }
71 }
72
73 void dfs2(int u,int tp)//将各个重节点连接成重链，轻节点连接成轻链，并且将重链(区间)用数据结构(一般是树状数组或者线段树)来维护，并且为每个节点进行编号，其实就是dfs在执行时的顺序(tid数组)，以及当前节点所在链的起点(top数组)还有当前节点在树中的位置(pos)                                                                                                                                                                                                                                                                                                                                                          )
74 {
75     top[u]=tp;//保存当前节点所在的链的顶端节点，当前节点的起点
76     tid[u]=++num;//保存树中每个节点剖分以后的新编号(dfs的执行顺序)
77     pos[tid[u]]=u;//保存当前节点在树中的位置，设置dfs序号对应成当前节点
78     if(son[u]==-1) return ;//如果当前节点没有处在重链上，则不处理
79     dfs2(son[u],tp);//将这条重链上的所有节点都设置成起始的重节点
81         int v=edge[i].to;//如果连接节点不是当前节点的重节点并且也不是u的父节点，则将其的top设置成自己，进一步递归
82         if(v!=son[u]&&v!=fa[u])
83             dfs2(v,v);
84     }
85 }
86
87 int lazy[maxn<<2],Max[maxn<<2],Min[maxn<<2];
88
89 //线段树部分
90 void Swap(int &x,int &y){int t=x;x=-y;y=-t;}
91
92 void pushup(int rt)
93 {
94     Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
95     Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
96 }
97
98 void pushdown(int rt)
99 {
100     if(lazy[rt]){
101         lazy[rt<<1]+=lazy[rt];
102         lazy[rt<<1|1]+=lazy[rt];
103         if(lazy[rt]&1){ //两个子区间是否取反依靠当前区间的懒惰标记判断,判断奇偶
104             Swap(Max[rt<<1],Min[rt<<1]);
105             Swap(Max[rt<<1|1],Min[rt<<1|1]);
106         }
107         lazy[rt]=0;
108     }
109 }
110
111 void build(int l,int r,int rt)
112 {
113     lazy[rt]=0;
114     if(l==r){
115         Max[rt]=Min[rt]=0;
116         return ;
117     }
118
119     int m=(l+r)>>1;
120     build(lson);
121     build(rson);
122     pushup(rt);
123 }
124
125 void update(int pos,int val,int l,int r,int rt)
126 {
127     if(l==r&&l==pos){
128         Max[rt]=val;Min[rt]=val;lazy[rt]=0;
129         return ;
130     }
131
132     pushdown(rt);
133     int m=(l+r)>>1;
134     if(pos<=m) update(pos,val,lson);
135     else       update(pos,val,rson);
136     pushup(rt);
137 }
138
139 void Negate(int L,int R,int l,int r,int rt)//Negate是int tmp=Max,Max=-Min,Min=-tmp
140 {
141     if(L<=l&&r<=R){
142         lazy[rt]++;
143         Swap(Max[rt],Min[rt]);//这里要马上取反
144         return ;
145     }
146
147     pushdown(rt);
148     int m=(l+r)>>1;
149     if(L<=m) Negate(L,R,lson);
150     if(R> m) Negate(L,R,rson);
151     pushup(rt);
152 }
153
154 int query(int L,int R,int l,int r,int rt)
155 {
156     if(L<=l&&r<=R){
157         return Max[rt];
158     }
159
160     pushdown(rt);
161     int ret=-inf;
162     int m=(l+r)>>1;
163     if(L<=m) ret=max(ret,query(L,R,lson));
164     if(R> m) ret=max(ret,query(L,R,rson));
165     pushup(rt);
166     return ret;
167 }
168
169 int get_max(int u,int v)
170 {
171     int ans=-1<<30;
172     while(top[u]!=top[v]){
173         if(dep[top[u]]<dep[top[v]]) swap(u,v);
174         ans=max(ans,query(tid[top[u]],tid[u],1,n,1));
175         u=fa[top[u]];
176     }
177
178     if(dep[v]<dep[u]) swap(u,v);
179     ans=max(ans,query(tid[son[u]],tid[v],1,n,1));//这里写捞了，tid[son[u]],写成tid[u],wa了好几天。。。
180     printf("%d
",ans);
181 }
182
183 void change(int u,int v)
184 {
185     while(top[u]!=top[v]){
186         if(dep[top[u]]<dep[top[v]]) swap(u,v);
187         Negate(tid[top[u]],tid[u],1,n,1);
188         u=fa[top[u]];
189     }
190
191     if(u==v) return ;
192     if(dep[v]<dep[u]) swap(u,v);
193     Negate(tid[son[u]],tid[v],1,n,1);
194 }
195
196 struct eg{
197     int u,v,val;
198 }eg[maxn];
199
200 int main()
201 {
202     int t;
203     scanf("%d",&t);
204     while(t--){
205         scanf("%d",&n);
206         init();
207         for(int i=1;i<n;i++){
208             scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].val);
211         }
212         dfs1(1,0);//第一遍dfs
213         dfs2(1,1);//第二遍dfs
214         build(1,n,1);
215         for(int i=1;i<n;i++){
216             if(dep[eg[i].u]<dep[eg[i].v]) swap(eg[i].u,eg[i].v);
217             update(tid[eg[i].u],eg[i].val,1,n,1);
218         }
219         int a,b;
220         char op[10];
221         while(scanf("%s",op)&&op[0]!='D'){
222             scanf("%d%d",&a,&b);
223             if(op[0]=='Q'){
224                 get_max(a,b);
225             }
226             if(op[0]=='C'){
227                 update(tid[eg[a].u],b,1,n,1);
228             }
229             if(op[0]=='N'){
230                 change(a,b);
231             }
232         }
233     }
234 }```

哈哈哈哈，加油加油。

• 相关阅读:
Linux基本常用知识整理
uva488 Triangle Wave