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 ...
随机推荐
- TCP通信的客户端代码实现和TCP通信的服务器代码实现
TCP通信的客户端代码实现 package com.yang.Test.ServerStudy; import java.io.*; import java.net.Socket; /** * TCP ...
- python opencv图像识别(相同大小图片)
简介 由于项目需要对比两张相同图片的相似度,因此采用opencv将图片转为灰阶数组,然后对比相应的数组来取相似度,此方法只适用于大小相同的图片,较为局限 # -*- coding: utf-8 -*- ...
- python编程思想及对象与类
目录 编程思想 面向对象 面向过程 对象与类的概念 对象与类的创建 对象的实例化方法-独有数据 编程思想 1.面向对象 1.1. 面向对象前戏 案例:人狗大战 # 需求:人狗大战# 1.'创造'出人和 ...
- Vue ref属性 && props配置项
1 // # ref属性: 2 // # 1.用来给元素或者子组件注册引用信息(id的替代者) 3 // # 2.应用在html标签上获取的是真实的DOM元素,应用在组件标签上是组件实例对象(vc) ...
- Java四大引用详解:强引用、软引用、弱引用、虚引用
面试官考察Java引用会问到强引用.弱引用.软引用.虚引用,具体有什么区别?本篇单独来详解 @mikechen Java引用 从JDK 1.2版本开始,对象的引用被划分为4种级别,从而使程序能更加灵活 ...
- Docker 03 镜像命令
参考源 https://www.bilibili.com/video/BV1og4y1q7M4?spm_id_from=333.999.0.0 https://www.bilibili.com/vid ...
- 使用 Golang 代码生成图表的开源库对比
本文的目标读者 对用 Golang 代码生成折线图.扇形图等图表有兴趣的朋友. 本文摘要 主要介绍 Go 中用以绘图的开源库,分别是: GitHub - wcharczuk/go-chart: go ...
- 简单概述 TCP/IP 协议簇
前言 通信协议是计算机之间交换信息所使用的一种公共语言的规范和约定.Internet 的通信协议包含 100 多种相互关联的协议,但是 TCP 和 IP 是其中两个最核心的关键协议,所以把 Inter ...
- MapReduce核心原理(下)
MapReduce 中的排序 MapTask 和 ReduceTask 都会对数据按key进行排序.该操作是 Hadoop 的默认行为,任何应用程序不管需不需要都会被排序.默认排序是字典顺序排序,排序 ...
- 面试突击77:Spring 依赖注入有几种?各有什么优缺点?
IoC 和 DI 是 Spring 中最重要的两个概念,其中 IoC(Inversion of Control)为控制反转的思想,而 DI(Dependency Injection)依赖注入为其(Io ...