通过打懒标记实现区间取反,和线段树基本操作都差不多。

本题还是一道边权化为点权的问题。

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 (树链剖分)的更多相关文章

  1. POJ3237 Tree 树链剖分 边权

    POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...

  2. POJ3237 Tree 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...

  3. Hdu 5274 Dylans loves tree (树链剖分模板)

    Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...

  4. Query on a tree——树链剖分整理

    树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...

  5. 【BZOJ-4353】Play with tree 树链剖分

    4353: Play with tree Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 31  Solved: 19[Submit][Status][ ...

  6. SPOJ Query on a tree 树链剖分 水题

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  7. poj 3237 Tree 树链剖分

    题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...

  8. Codeforces Round #200 (Div. 1) D Water Tree 树链剖分 or dfs序

    Water Tree 给出一棵树,有三种操作: 1 x:把以x为子树的节点全部置为1 2 x:把x以及他的所有祖先全部置为0 3 x:询问节点x的值 分析: 昨晚看完题,马上想到直接树链剖分,在记录时 ...

  9. poj 3237 Tree 树链剖分+线段树

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

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

随机推荐

  1. 2505-springboot使用spring.profiles.active来分区配置

    参考文献: spring boot 入门 使用spring.profiles.active来分区配置 http://www.leftso.com/blog/111.html 很多时候,我们项目在开发环 ...

  2. scrollTop实例

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  3. 线程本地存储 ThreadLocal

    线程本地存储 · 语雀 (yuque.com) 线程本地存储提供了线程内存储变量的能力,这些变量是线程私有的. 线程本地存储一般用在跨类.跨方法的传递一些值. 线程本地存储也是解决特定场景下线程安全问 ...

  4. ETCD快速入门-03 常用命令

    3. ETCD 常用命令     etcdctl是一个命令行的客户端,它提供了一些命令,可以方便我们在对服务进行测试或者手动修改数据库内容.etcdctl与kubectl和systemctl的命令原理 ...

  5. Taurus.MVC 微服务框架 入门开发教程:项目部署:3、微服务应用程序版本升级:全站升级和局部模块升级。

    系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...

  6. 使用JMeter测试.Net5.0,.Net6.0框架下无数据处理的并发情况

    1.   安装JMeter及使用 1.1下载JMeter 登录官方网站找到下载链接进行下载:https://jmeter.apache.org/download_jmeter.cgi 1.2配置环境变 ...

  7. HTML短链接

    短链接跳转方法 新建一个目录名称就是短链接字符列如:1 创建一个index.html文件里面添加代码如下 <script type="text/javascript"> ...

  8. JS/java实现QQ空间自动点赞

    使用方法: 1:进入QQ空间 2:复制下面代码 3:按F12或右键审查元素 进入控制台 也就是console 4:粘贴  回车键  喝口水 5:如果嫌慢的话可以 修改这段代码. window.setI ...

  9. 基于开源方案构建统一的文件在线预览与office协同编辑平台的架构与实现历程

    大家好,又见面了. 在构建业务系统的时候,经常会涉及到对附件的支持,继而又会引申出对附件在线预览.在线编辑.多人协同编辑等种种能力的诉求. 对于人力不是特别充裕.或者项目投入预期规划不是特别大的公司或 ...

  10. python脚本将json文件生成C语言结构体

    1.引言 以前用过python脚本根据excel生成相关C语言代码,其实本质就是文件的读写,主要是逻辑问题,这次尝试将json文件生成C语言的结构体. 2.代码 这是一个json文件,生成这个结构体的 ...