POJ3237 Tree (树链剖分)
通过打懒标记实现区间取反,和线段树基本操作都差不多。
本题还是一道边权化为点权的问题。
200行巨长代码:
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5 const int maxn=10010;
6 int head[maxn],cnt=0,total=0;//头结点
7 int fa[maxn],dep[maxn];//父亲,深度
8 int size[maxn],son[maxn],top[maxn];//子树结点总数,重儿子,所在重链顶端结点
9 int id[maxn],rev[maxn];//u对应的dfs序下标,下标对于的u
10 int Max;
11 struct Edge{
12 int u,v,w;
13 }a[maxn];
14
15 struct edge{
16 int to,next;
17 }e[maxn<<1];
18
19 struct node{//结点
20 int l,r,Max,Min,lazy;//l,r区间左右端点,区间最值 ,懒标记
21 }tree[maxn<<2]; //树结点存储数组
22
23 void add(int u,int v){
24 e[++cnt].to=v;
25 e[cnt].next=head[u];
26 head[u]=cnt;
27 }
28
29 void init(){
30 cnt=total=0;
31 memset(head,0,sizeof(head));
32 memset(son,0,sizeof(son));
33 }
34
35 void dfs1(int u,int f){//求dep,fa,size,son
36 size[u]=1;
37 for(int i=head[u];i;i=e[i].next){
38 int v=e[i].to;
39 if(v==f)//父节点
40 continue;
41 dep[v]=dep[u]+1;//深度
42 fa[v]=u;
43 dfs1(v,u);
44 size[u]+=size[v];
45 if(size[v]>size[son[u]])
46 son[u]=v;
47 }
48 }
49
50 void dfs2(int u,int t){//求top,id
51 top[u]=t;
52 id[u]=++total;//u对应的dfs序下标
53 rev[total]=u;//dfs序下标对应的结点u
54 if(!son[u])
55 return;
56 dfs2(son[u],t);//沿着重儿子dfs
57 for(int i=head[u];i;i=e[i].next){
58 int v=e[i].to;
59 if(v!=fa[u]&&v!=son[u])
60 dfs2(v,v);
61 }
62 }
63
64 void build(int i,int l,int r){//初始化线段树,i表示存储下标,区间[l,r]
65 tree[i].l=l;
66 tree[i].r=r;
67 tree[i].Max=tree[i].Min=tree[i].lazy=0;
68 if(l==r) return;
69 int mid=(l+r)/2;//划分点
70 build(i<<1,l,mid);
71 build((i<<1)|1,mid+1,r);
72 }
73
74 void push_up(int i){//上传
75 tree[i].Max=max(tree[i<<1].Max,tree[(i<<1)|1].Max);
76 tree[i].Min=min(tree[i<<1].Min,tree[(i<<1)|1].Min);
77 }
78
79 void push_down(int i){//下传
80 if(tree[i].l==tree[i].r) return;
81 if(tree[i].lazy){//下传给左右孩子,懒标记清零
82 tree[i<<1].Max=-tree[i<<1].Max;
83 tree[i<<1].Min=-tree[i<<1].Min;
84 swap(tree[i<<1].Min,tree[i<<1].Max);
85 tree[(i<<1)|1].Max=-tree[(i<<1)|1].Max;
86 tree[(i<<1)|1].Min=-tree[(i<<1)|1].Min;
87 swap(tree[(i<<1)|1].Max,tree[(i<<1)|1].Min);
88 tree[i<<1].lazy^=1;
89 tree[(i<<1)|1].lazy^=1;
90 tree[i].lazy=0;
91 }
92 }
93
94 void update(int i,int k,int val){//点更新,线段树的第k个值为val
95 if(tree[i].l==k&&tree[i].r==k){
96 tree[i].Max=val;
97 tree[i].Min=val;
98 tree[i].lazy=0;
99 return;
100 }
101 push_down(i);
102 int mid=(tree[i].l+tree[i].r)/2;
103 if(k<=mid) update(i<<1,k,val);
104 else update((i<<1)|1,k,val);
105 push_up(i);
106 }
107
108 void update2(int i,int l,int r){//区间更新,线段树的区间[l,r]取反
109 if(tree[i].l>=l&&tree[i].r<=r){
110 tree[i].Max=-tree[i].Max;
111 tree[i].Min=-tree[i].Min;
112 swap(tree[i].Max,tree[i].Min);
113 tree[i].lazy^=1;
114 return;//取反并打上标记
115 }
116 push_down(i);//下传标记
117 int mid=(tree[i].l+tree[i].r)/2;
118 if(l<=mid) update2(i<<1,l,r);
119 if(r>mid) update2((i<<1)|1,l,r);
120 push_up(i);
121 }
122
123 void query(int i,int l,int r){//查询线段树中[l,r]的最大值
124 if(tree[i].l>=l&&tree[i].r<=r){//找到该区间
125 Max=max(Max,tree[i].Max);
126 return;
127 }
128 push_down(i);//下传标记
129 int mid=(tree[i].l+tree[i].r)/2;
130 if(l<=mid) query(i<<1,l,r);
131 if(r>mid) query((i<<1)|1,l,r);
132 push_up(i);
133 }
134
135 void ask(int u,int v){//求u,v之间的最值
136 while(top[u]!=top[v]){//不在同一条重链上
137 if(dep[top[u]]<dep[top[v]])
138 swap(u,v);
139 query(1,id[top[u]],id[u]);//u顶端结点和u之间
140 u=fa[top[u]];
141 }
142 if(u==v) return;
143 if(dep[u]>dep[v])//在同一条重链上
144 swap(u,v); //深度小的结点为u
145 query(1,id[son[u]],id[v]);//注意是son[u]
146 }
147
148 void Negate(int u,int v){//把u-v路径上的边的值取相反数
149 while(top[u]!=top[v]){//不在同一条重链上
150 if(dep[top[u]]<dep[top[v]])
151 swap(u,v);
152 update2(1,id[top[u]],id[u]);//u顶端结点和u之间
153 u=fa[top[u]];
154 }
155 if(u==v) return; //不要忘了加上这一步
156 if(dep[u]>dep[v])//在同一条重链上
157 swap(u,v); //深度小的结点为u
158 update2(1,id[son[u]],id[v]);//注意是son[u]
159 }
160
161 int main(){
162 int T,n;
163 scanf("%d",&T);
164 while(T--){
165 init();
166 scanf("%d",&n);
167 for(int i=1;i<n;i++){
168 scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
169 add(a[i].u,a[i].v);
170 add(a[i].v,a[i].u);
171 }
172 dep[1]=1;
173 dfs1(1,0);
174 dfs2(1,1);
175 build(1,1,total);//创建线段树
176 for(int i=1;i<n;i++){//边权化为点权
177 if(dep[a[i].u]>dep[a[i].v])
178 swap(a[i].u,a[i].v);
179 update(1,id[a[i].v],a[i].w);
180 }
181 char op[10];
182 int u,v;
183 while(scanf("%s",op)==1){
184 if(op[0]=='D')break;
185 scanf("%d%d",&u,&v);
186 if(op[0]=='Q'){
187 Max=-0x3f3f3f3f;
188 ask(u,v);//查询u->v路径上边权的最大值
189 printf("%d\n",Max);
190 }
191 else if(op[0]=='C')
192 update(1,id[a[u].v],v);//改变第u条边的值为v
193 else Negate(u,v);//区间取反
194 }
195 }
196 return 0;
197 }
POJ3237 Tree (树链剖分)的更多相关文章
- POJ3237 Tree 树链剖分 边权
POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...
- POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
- Hdu 5274 Dylans loves tree (树链剖分模板)
Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...
- Query on a tree——树链剖分整理
树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...
- 【BZOJ-4353】Play with tree 树链剖分
4353: Play with tree Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 31 Solved: 19[Submit][Status][ ...
- SPOJ Query on a tree 树链剖分 水题
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- poj 3237 Tree 树链剖分
题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...
- Codeforces Round #200 (Div. 1) D Water Tree 树链剖分 or dfs序
Water Tree 给出一棵树,有三种操作: 1 x:把以x为子树的节点全部置为1 2 x:把x以及他的所有祖先全部置为0 3 x:询问节点x的值 分析: 昨晚看完题,马上想到直接树链剖分,在记录时 ...
- poj 3237 Tree 树链剖分+线段树
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
随机推荐
- 教你PC端网易云音乐自定义代理,VIP免费听歌!
今天分享一份福利吧,使用网易云音乐自定义代理实现免费听和下载VIP.极高音质.付费的歌曲,这里主要针对PC端电脑版的,需要自己写脚本运行. 01 安装node.js Node.js是一个让 JavaS ...
- 丽泽普及2022交流赛day20 1/4社论
目录 T1 正方形 T2 玩蛇 T3 嗷呜 T4 开车 T1 正方形 略 T2 玩蛇 略 T3 嗷呜 (插一个删一个?) 找出相同的,丢掉循环节 . 感觉非常离谱,,, 正确性存疑 正确性问 SoyT ...
- 使用Python3.7+Tornado5.1集成新浪微博三方登录(无需企业资质)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_137 新浪微博:山寨版的twitter,各种粉丝的集散地,天朝人民的最爱,基本上网民都人手一个微博账号,所以使用新浪微博账号进行三 ...
- 金瓯无缺江河一统|Win10系统基于Docker和Python3搭建并维护统一认证系统OpenLdap
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_180 OpenLdap(Lightweight Directory Access Protocol)是什么?它其实是一个开源的.具 ...
- 多云部署多主模式的MGR集群,每个云一个MGR 节点,满足业务单元化改造的需求
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 本 ...
- Java 注解及其底层原理
目录 什么是注解? 注解的分类 Java自带的标准注解 元注解 @Retention @Documented @Target @Inherited @Repeatable 自定义注解 自定义注解的读取 ...
- 零基础学Java(14)对象构造
对象构造 之前学习了编写简单的构造器,可以定义对象的初始状态.但是,由于对象构造非常重要,所以Java提供了多种编写构造器的机制. 重载 有些类有多个构造器.例如,可以如下构造一个空的StringBu ...
- 人人都能看懂的卡西欧fx991cnx玩机指南,手把手教你如何利用计算器的漏洞爆机
专业术语说明 你是VerB还是VerC 别人问你这个问题的时候不要慌,帮你看你的计算器是Ver几: 同时按住shift.7.开机键 9 5次shift 第一行后半句即是 紧接着可以顺便看看计算器的序列 ...
- 「题解报告」SP16185 Mining your own business
题解 SP16185 Mining your own business 原题传送门 题意 给你一个无向图,求至少安装多少个太平井,才能使不管那个点封闭,其他点都可以与有太平井的点联通. 题解 其他题解 ...
- openstack中Glance组件简解
一.Glance组件介绍 1.概念 Glance是OpenStack镜像服务,用来注册.登陆和检索虚拟机镜像.Glance服务提供了一个REST API,使你能够查询虚拟机镜像元数据和检索的实际镜像. ...