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 ...
随机推荐
- 三万字盘点Spring/Boot的那些常用扩展点
大家好,我是三友. Spring对于每个Java后端程序员来说肯定不陌生,日常开发和面试必备的.本文就来盘点Spring/SpringBoot常见的扩展点,同时也来看看常见的开源框架是如何基于这些扩展 ...
- React报错之Property 'X' does not exist on type 'HTMLElement'
正文从这开始~ 总览 在React中,当我们试图访问类型为HTMLElement 的元素上不存在的属性时,就会发生Property 'X' does not exist on type 'HTMLEl ...
- Python3+Django2集成PayPal(贝宝)跨境支付三方接口以及订单查询和退款业务
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_157 如果您所在的公司涉及外贸或者跨境支付业务,那一定听说过大名鼎鼎的PayPal,总的来说,PayPal在跨国贸易里的优势还是比 ...
- Charles自动保存响应数据
本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! 操作环境 win10 nexus5x c ...
- C++封装静态链接库和使用
零碎记事 距离上次发博客已经有一年半了,转眼间我也是从做图像研究到了做游戏开发,说起来看看前面的博文,本来就有前兆的东西呢(笑)......因为主要还是在使用虚幻引擎,所以C++的东西会碰到多一些. ...
- WTL_Freecell绿色版
WTL_Freecell绿色版-用户手册 1.程序特点和使用环境介绍 (1).版本信息 WTL_Freecell-Release05-v1.3-20190129 (WTL空当接龙绿色版v1.3),By ...
- 《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(11)-Fiddler设置安卓手机抓包,不会可是万万不行的!
1.简介 Fiddler不但能截获各种浏览器发出的 HTTP 请求,也可以截获各种智能手机发出的HTTP/ HTTPS 请求. Fiddler能截获 Android 和 Windows Phone 等 ...
- Taurus.MVC WebAPI 入门开发教程6:全局控制器DefaultController与全局事件。
系列目录 1.Taurus.MVC WebAPI 入门开发教程1:框架下载环境配置与运行. 2.Taurus.MVC WebAPI 入门开发教程2:添加控制器输出Hello World. 3.Tau ...
- Redis的两种持久化机制
Redis的两种持久化机制 1.持久化机制 client--->redis(内存)--->内存数据-数据持久化--->磁盘 两种方法 快照(Snapshot) AOF(Append ...
- 分布式id生成器,雪花算法IdWorker
/** * <p>名称:IdWorker.java</p> * <p>描述:分布式自增长ID</p> * <pre> * Twitter的 ...