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

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

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. SpringCloud gateway自定义请求的 httpClient

    本文为博主原创,转载请注明出处: 引用 的 spring cloud gateway 的版本为 2.2.5 : SpringCloud gateway 在实现服务路由并请求的具体过程是在 org.sp ...

  2. 技术分享 | MySQL Group Replication集群对IP地址的限制导致的一些问题与解决办法

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1. 遇到问题 测试人员小玲准备在docker环境中部署MGR集群进行一些测试,她有三个容器,容器IP分别是: 172.3 ...

  3. 万答#4,延迟从库加上MASTER_DELAY,主库宕机后如何快速恢复服务

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 当主库宕机后,延迟从库如何才能"取消"主动延迟,以便恢复服务 ...

  4. Reactive UI -- 反应式编程UI框架入门学习(一)

    推荐一个反应式编程的MVVM跨平台框架. 反应式编程 反应式编程是一种相对于命令式的编程范式,由函数式的组合声明来构建异步数据流.要理解这个概念,可以简单的借助Excel中的单元格函数. 上图中,A1 ...

  5. 我和Apache DolphinScheduler的缘分

    关于 DolphinScheduler社区 Apache DolphinScheduler(incubator) 于17年在易观数科立项,19年3月开源, 19 年8月进入Apache 孵化器,社区发 ...

  6. CF906C Party (状压DP)(未完成//鬼知道啥情况)

    CF上下了数据,本地能过,一交就错 这状压不用解释,看代码就懂. #include <iostream> #include <cstdio> #include <cstr ...

  7. 综合布线 子网掩码 IP地址 子网划分

    1.1 地址协议 ipv4 :目前主流的协议 2. ipv6 :fe80::fe7:ca03:81f:2887 2 128 IANA(The Internet Assigned Numbers Aut ...

  8. 面试突击80:说一下 Spring 中 Bean 的生命周期?

    Java 中的公共类称之为 Bean 或 Java Bean,而 Spring 中的 Bean 指的是将对象的生命周期,交个 Spring IoC 容器来管理的对象.所以 Spring 中的 Bean ...

  9. mysql8.0及以上修改Root密码

    ALTER user 'root'@'localhost' IDENTIFIED BY 'Cliu123#' //1.不需要flush privileges来刷新权限. //2.密码要包含大写字母,小 ...

  10. vscode常用快捷键及插件

    macOS 全局 Command + Shift + P / F1 显示命令面板 Command + P 快速打开 Command + Shift + N 打开新窗口 Command + W 关闭窗口 ...