POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

题目链接:http://poj.org/problem?id=3237

一棵有边权的树,有3种操作。

树链剖分+线段树lazy标记。lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每次更新异或1就可以。

熟悉线段树成段更新就很简单了,最初姿势不对一直wa,还是没有彻底理解lazy标记啊。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 using namespace std;
  5 const int MAXN = 1e4 + 5;
  6 struct EDGE {
  7     int next , to , cost;
  8 }edge[MAXN << 1];
  9 int head[MAXN] , tot;
 10 int par[MAXN] , size[MAXN] , son[MAXN] , dep[MAXN];
 11 int top[MAXN] , id[MAXN] , cnt;
 12 int from[MAXN] , to[MAXN] , cost[MAXN];
 13
 14 void init() {
 15     tot = cnt = 0;
 16     memset(head , -1 , sizeof(head));
 17 }
 18
 19 inline void add(int u , int v , int cost) {
 20     edge[tot].next = head[u];
 21     edge[tot].to = v;
 22     head[u] = tot++;
 23 }
 24
 25 void dfs1(int u , int p , int d) {
 26     par[u] = p , size[u] = 1 , son[u] = u , dep[u] = d;
 27     for(int i = head[u] ; ~i ; i = edge[i].next) {
 28         int v = edge[i].to;
 29         if(v == p)
 30             continue;
 31         dfs1(v , u , d + 1);
 32         if(size[v] >= size[son[u]])
 33             son[u] = v;
 34         size[u] += size[v];
 35     }
 36 }
 37
 38 void dfs2(int u , int p , int t) {
 39     top[u] = t , id[u] = ++cnt;
 40     if(son[u] != u)
 41         dfs2(son[u] , u , t);
 42     for(int i = head[u] ; ~i ; i = edge[i].next) {
 43         int v = edge[i].to;
 44         if(v == p || v == son[u])
 45             continue;
 46         dfs2(v , u , v);
 47     }
 48 }
 49
 50 struct SegTree {
 51     int l , r , Max , lazy , Min; //lazy变量0表示无更新 1表示有更新
 52 }T[MAXN << 2];
 53
 54 void build(int p , int l , int r) {
 55     int mid = (l + r) >> 1;
 56     T[p].l = l , T[p].r = r , T[p].lazy = 0;
 57     if(l == r) {
 58         return ;
 59     }
 60     build(p << 1 , l , mid);
 61     build((p << 1)|1 , mid + 1 , r);
 62 }
 63
 64 void pushup(int p) {
 65     if(T[p].lazy) {
 66         int ls = p << 1 , rs = (p << 1)|1;
 67         T[ls].lazy ^= 1;
 68         T[rs].lazy ^= 1;
 69
 70         int temp;
 71         temp = T[ls].Max;
 72         T[ls].Max = -T[ls].Min;
 73         T[ls].Min = -temp;
 74
 75         temp = T[rs].Max;
 76         T[rs].Max = -T[rs].Min;
 77         T[rs].Min = -temp;
 78         T[p].lazy = 0;
 79     }
 80 }
 81 //更新操作就是 将原来的Max变成-Min ,Min变成-Max
 82 void updata(int p , int l , int r , int flag) {
 83     int mid = (T[p].r + T[p].l) >> 1;
 84     if(T[p].l == l && T[p].r == r) {
 85         T[p].lazy ^= flag;
 86         int temp = T[p].Max;
 87         T[p].Max = -T[p].Min;
 88         T[p].Min = -temp;
 89         return ;
 90     }
 91     pushup(p);
 92     if(r <= mid) {
 93         updata(p << 1 , l , r , flag);
 94     }
 95     else if(l > mid) {
 96         updata((p << 1)|1 , l , r , flag);
 97     }
 98     else {
 99         updata(p << 1 , l , mid , flag);
100         updata((p << 1)|1 , mid + 1 , r , flag);
101     }
102     T[p].Max = max(T[p << 1].Max , T[(p << 1)|1].Max);
103     T[p].Min = min(T[p << 1].Min , T[(p << 1)|1].Min);
104 }
105
106 int query(int p , int l , int r) {
107     int mid = (T[p].l + T[p].r) >> 1;
108     if(T[p].l == l && T[p].r == r) {
109         return T[p].Max;
110     }
111     pushup(p);
112     if(r <= mid) {
113         return query(p << 1 , l , r);
114     }
115     else if(l > mid) {
116         return query((p << 1)|1 , l , r);
117     }
118     else {
119         return max(query(p << 1 , l , mid) , query((p << 1)|1 , mid + 1 , r));
120     }
121 }
122
123 void updata_pos(int p , int pos , int num) {
124     int mid = (T[p].l + T[p].r) >> 1;
125     if(T[p].l == T[p].r && T[p].l == pos) {
126         T[p].Max = T[p].Min = num;
127         T[p].lazy = 0;
128         return ;
129     }
130     pushup(p);
131     if(pos <= mid) {
132         updata_pos(p << 1 , pos , num);
133     }
134     else {
135         updata_pos((p << 1)|1 , pos , num);
136     }
137     T[p].Max = max(T[p << 1].Max , T[(p << 1)|1].Max);
138     T[p].Min = min(T[p << 1].Min , T[(p << 1)|1].Min);
139 }
140
141 int find_max(int u , int v) {
142     int fu = top[u] , fv = top[v] , Max = -99999999;
143     while(fv != fu) {
144         if(dep[fu] > dep[fv]) {
145             Max = max(Max , query(1 , id[fu] , id[u]));
146             u = par[fu];
147             fu = top[u];
148         }
149         else {
150             Max = max(Max , query(1 , id[fv] , id[v]));
151             v = par[fv];
152             fv = top[v];
153         }
154     }
155     if(v == u)
156         return Max;
157     else if(dep[u] > dep[v])
158         return max(Max , query(1 , id[son[v]] , id[u]));
159     else
160         return max(Max , query(1 , id[son[u]] , id[v]));
161 }
162
163 void change(int u , int v) {
164     int fu = top[u] , fv = top[v];
165     while(fu != fv) {
166         if(dep[fu] > dep[fv]) {
167             updata(1 , id[fu] , id[u] , 1);
168             u = par[fu];
169             fu = top[u];
170         }
171         else {
172             updata(1 , id[fv] , id[v] , 1);
173             v = par[fv];
174             fv = top[v];
175         }
176     }
177     if(v == u)
178         return ;
179     else if(dep[u] > dep[v])
180         updata(1 , id[son[v]] , id[u] , 1);
181     else
182         updata(1 , id[son[u]] , id[v] , 1);
183 }
184
185 int main()
186 {
187     int t, n;
188     scanf("%d", &t);
189     while(t--) {
190         init();
191         scanf("%d" , &n);
192         for(int i = 1 ; i < n ; ++i) {
193             scanf("%d %d %d" , from + i , to + i , cost + i);
194             add(from[i] , to[i] , cost[i]);
195             add(to[i] , from[i] , cost[i]);
196         }
197         dfs1(1 , 1 , 0);
198         dfs2(1 , 1 , 1);
199         build(1 , 2 , cnt);
200         for(int i = 1 ; i < n ; ++i) {
201             if(dep[from[i]] < dep[to[i]])
202                 swap(from[i] , to[i]);
203             updata_pos(1 , id[from[i]] , cost[i]);
204         }
205         char q[10];
206         int l , r;
207         while(scanf("%s" , q) && q[0] != ‘D‘) {
208             scanf("%d %d" , &l , &r);
209             if(q[0] == ‘Q‘) {
210                 printf("%d\n" , find_max(l , r));
211             }
212             else if(q[0] == ‘N‘) {
213                 change(l , r);
214             }
215             else {
216                 updata_pos(1 , id[from[l]] , r);
217             }
218         }
219     }
220     return 0;
221 }
时间: 2025-01-05 12:28:51

POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)的相关文章

【Hihocoder 1167】 高等理论计算机科学 (树链的交,线段树或树状数组维护区间和)

[题意] 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 少女幽香这几天正在学习高等理论计算机科学,然而她什么也没有学会,非常痛苦.所以她出去晃了一晃,做起了一些没什么意义的事情来放松自己.门前有一颗n个节点树,幽香发现这个树上有n个小精灵.然而这些小精灵都比较害羞,只会在一条特定的路径上活动.第i个小精灵会在ai到bi的路径上活动.两个小精灵是朋友,当且仅当它们的路径是有公共点的.于是幽香想要知道,有多少对小精灵a和b,a和b是朋友呢?其中a不等于b,a,b和b,

poj 3237 Tree(树链拆分)

题目链接:poj 3237 Tree 题目大意:给定一棵树,三种操作: CHANGE i v:将i节点权值变为v NEGATE a b:将ab路径上全部节点的权值变为相反数 QUERY a b:查询ab路径上节点权值的最大值. 解题思路:树链剖分.然后用线段树维护节点权值,成端更新查询. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int max

(树链剖分+线段树)POJ - 3237 Tree

前言: 一直听说树链剖分-树链剖分,现在见识一下,,,感觉不是很难0.0 看了一下kuangbin模板基本秒懂 对于点,按重边优先给予每个点一个编号,对于一条重链上的点,编号则是连续的,将所有编号映射到线段树上,即可进行一切区间操作. 对于边的处理,我们将所有边对应到这条边节点更深的那个点上即可. 如果需要的操作只有求和,和单点更新/区间更新,直接用树状数组也是可以的,可能常数大那么一点点. 如果还需要更加强大的操作,显然用splay树维护也是可以的.. 比如树链上所有权值翻转等等..不过,,这

BZOJ 2243:染色(树链剖分+区间合并线段树)

[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”.请你写一个程序依次完成这m个操作.Input第一行包含2个整数n和m,分别表示节点数和操作数:第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.下面 行每行描述一个操作:“C

BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2243 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写

HDU 3966 Aragorn&#39;s Story (树链点权剖分,成段修改单点查询)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 树链剖分的模版,成段更新单点查询.熟悉线段树的成段更新的话就小case啦. 1 //树链剖分 边权修改 单点查询 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespace std; 7 const int M

【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流

[BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一天,她准备去探访他.对着窗外的阳光,临行前她再次弹起了琴.她的琴的发声十分特殊.让我们给一个形式化的定义吧.所有的 n 个音符形成一棵由音符 C ( 1 号节点) 构成的有根树,每一个音符有一个音高 Hi .Arietta 有 m 个力度,第 i 个力度能弹出 Di 节点的子树中,音高在 [Li,R

POJ 2886 Who Gets the Most Candies?(线段树模拟约瑟夫环,高合成数)

POJ 2886 Who Gets the Most Candies?(线段树模拟约瑟夫环,高合成数) ACM 题目地址:POJ 2886 Who Gets the Most Candies? 题意: N 个小孩围成一圈,他们被顺时针编号为 1 到 N.每个小孩手中有一个卡片,上面有一个非 0 的数字,游戏从第 K 个小孩开始,他告诉其他小孩他卡片上的数字并离开这个圈,他卡片上的数字 A 表明了下一个离开的小孩,如果 A 是大于 0 的,则下个离开的是左手边第 A 个,如果是小于 0 的, 则是

POJ 3468 A Simple Problem with Integers(线段树)

题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 56005   Accepted: 16903 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with

【POJ 2482】 Stars in Your Window(线段树+离散化+扫描线)

[POJ 2482] Stars in Your Window(线段树+离散化+扫描线) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11294   Accepted: 3091 Description Fleeting time does not blur my memory of you. Can it really be 4 years since I first saw you? I still remembe