【BZOJ2157】旅游,树链剖分练习
传送门
写在前面:模拟赛中CA爷卡我内存,暴力100变60……不过还是亲学长(毕竟在我初中的时候就是学长),每次做CA爷的题都是高分……
思路:
(迄今做的最爽的树链剖分)
被char哥带着做这道题,结果耗了好久时间调好,这应该是第一次写边链剖了?与点链剖不同的是要处理下边(深度大的变成入点),然后建树时,这个入点的权值就是边的权值(根的权值为0)。查询时,最后l,r到同一条链上来,要让l赋为l的重儿子,然后再求值(如果l,r是同一个点就直接退出,不用赋值重儿子了,因为相同的点之间没有路径权值)
其他就是简单的加标记求最大最小与总和了,这个题多一步取反操作,直接打标记,最大值最小值交换,然后最大最小与总和全部取相反数就行了
注意:读入判断命令要注意……
代码:
#include<bits/stdc++.h>
#define Inf 0x7fffffff
using namespace std;
int n,m,tot,cnt;
char ch;
int val[20010],L[20010],first[20010],pre[20010],dep[20010],siz[20010],top[20010],fa[20010],son[20010];
struct edge
{int u,v,w,next;
}e[40010];
struct node
{int sum,maxn,minn;bool lazy;
}tree[100010];
void add(int x,int y,int z)
{e[++tot].u=x;e[tot].v=y;e[tot].w=z;e[tot].next=first[x];first[x]=tot;
}
void dfs1(int now)
{siz[now]=1;for (int i=first[now];i;i=e[i].next)if (fa[now]!=e[i].v){dep[e[i].v]=dep[now]+1;fa[e[i].v]=now;dfs1(e[i].v);siz[now]+=siz[e[i].v];if (siz[e[i].v]>siz[son[now]]) son[now]=e[i].v;}
}
void dfs2(int now,int tp)
{top[now]=tp;pre[++cnt]=now;L[now]=cnt;if (son[now]) dfs2(son[now],tp);for (int i=first[now];i;i=e[i].next)if (e[i].v!=fa[now]&&e[i].v!=son[now])dfs2(e[i].v,e[i].v);
}
void pushdown(int now)
{if (!tree[now].lazy) return;tree[now<<1].lazy^=1;tree[now<<1|1].lazy^=1;swap(tree[now<<1].maxn,tree[now<<1].minn);tree[now<<1].maxn=-tree[now<<1].maxn;tree[now<<1].minn=-tree[now<<1].minn;tree[now<<1].sum=-tree[now<<1].sum;swap(tree[now<<1|1].maxn,tree[now<<1|1].minn);tree[now<<1|1].maxn=-tree[now<<1|1].maxn;tree[now<<1|1].minn=-tree[now<<1|1].minn;tree[now<<1|1].sum=-tree[now<<1|1].sum;tree[now].lazy=0;
}
void pushup(int now)
{tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;tree[now].maxn=max(tree[now<<1].maxn,tree[now<<1|1].maxn);tree[now].minn=min(tree[now<<1].minn,tree[now<<1|1].minn);
}
void build(int now,int begin,int end)
{if (begin==end) {tree[now].sum=tree[now].minn=tree[now].maxn=val[pre[end]];return;}int mid=(begin+end)>>1;build(now<<1,begin,mid);build(now<<1|1,mid+1,end);pushup(now);
}
void update(int now,int begin,int end,int pos,int num)
{if (begin==end) {tree[now].lazy=0;tree[now].sum=tree[now].minn=tree[now].maxn=num;return;}pushdown(now);int mid=(begin+end)>>1;if (mid>=pos) update(now<<1,begin,mid,pos,num);else update(now<<1|1,mid+1,end,pos,num);pushup(now);
}
void oppo(int now,int begin,int end,int l,int r)
{if (l<=begin&&end<=r){tree[now].lazy^=1;tree[now].sum=-tree[now].sum;swap(tree[now].minn,tree[now].maxn);tree[now].minn=-tree[now].minn;tree[now].maxn=-tree[now].maxn;return;}pushdown(now);int mid=(begin+end)>>1;if (mid>=l) oppo(now<<1,begin,mid,l,r);if (mid<r) oppo(now<<1|1,mid+1,end,l,r);pushup(now);
}
int get_max(int now,int begin,int end,int l,int r)
{if (l<=begin&&end<=r) return tree[now].maxn;pushdown(now);int ans=-Inf,mid=(begin+end)>>1;if (mid>=l) ans=max(get_max(now<<1,begin,mid,l,r),ans);if (mid<r) ans=max(get_max(now<<1|1,mid+1,end,l,r),ans);return ans;
}
int get_min(int now,int begin,int end,int l,int r)
{if (l<=begin&&end<=r) return tree[now].minn;pushdown(now);int ans=Inf,mid=(begin+end)>>1;if (mid>=l) ans=min(get_min(now<<1,begin,mid,l,r),ans);if (mid<r) ans=min(get_min(now<<1|1,mid+1,end,l,r),ans);return ans;
}
int get_sum(int now,int begin,int end,int l,int r)
{if (l<=begin&&end<=r) return tree[now].sum;pushdown(now);int ans=0,mid=(begin+end)>>1;if (mid>=l) ans+=get_sum(now<<1,begin,mid,l,r);if (mid<r) ans+=get_sum(now<<1|1,mid+1,end,l,r);return ans;
}
void solve(int l,int r)
{int minn=Inf,maxn=-Inf,ans=0,f1=top[l],f2=top[r];while (f1!=f2){if (dep[f1]<dep[f2]) swap(f1,f2),swap(l,r);if (ch=='N') oppo(1,1,cnt,L[f1],L[l]);else if (ch=='S') ans+=get_sum(1,1,cnt,L[f1],L[l]);else if (ch=='I') minn=min(minn,get_min(1,1,cnt,L[f1],L[l]));else maxn=max(maxn,get_max(1,1,cnt,L[f1],L[l]));l=fa[f1];f1=top[l];}if (dep[l]>dep[r]) swap(l,r);if (l==r){if (ch=='S') {printf("%d\n",ans);return;}if (ch=='I') {printf("%d\n",minn);return;}if (ch=='A') {printf("%d\n",maxn);return;}}l=son[l];if (ch=='N') oppo(1,1,cnt,L[l],L[r]);else if (ch=='S') ans+=get_sum(1,1,cnt,L[l],L[r]),printf("%d\n",ans);else if (ch=='I') minn=min(minn,get_min(1,1,cnt,L[l],L[r])),printf("%d\n",minn);else if (ch=='A')maxn=max(maxn,get_max(1,1,cnt,L[l],L[r])),printf("%d\n",maxn);
}
main()
{scanf("%d",&n);int x,y,z;for (int i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),x++,y++,add(x,y,z),add(y,x,z);dfs1(1);dfs2(1,1);for (int i=1;i<=tot;i++){if (dep[e[i].u]>dep[e[i].v]) swap(e[i].u,e[i].v);val[e[i].v]=e[i].w;}build(1,1,cnt);scanf("%d",&m);while (m--){ch=getchar();while (ch!='S'&&ch!='C'&&ch!='M'&&ch!='N') ch=getchar();if (ch=='C') {scanf("%d%d",&x,&y);update(1,1,cnt,L[e[x<<1].v],y);continue;}else if (ch=='S') getchar(),getchar();else if (ch=='M') ch=getchar(),getchar();scanf("%d%d",&x,&y);solve(x+1,y+1);}
}
【BZOJ2157】旅游,树链剖分练习相关推荐
- P1505 [国家集训队]旅游 树链剖分
题目链接 题意:树上更新某一点权值,更新两点简单路径权值,查询最大,最小,和 思路:思路应该比较简单,就是树链剖分后用线段树维护区间最大最小以及区间和. 但是本题比较特殊的是给的边权,转化为点权即可. ...
- ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】
题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...
- bzoj 3999: [TJOI2015]旅游(树链剖分)
3999: [TJOI2015]旅游 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 423 Solved: 214 [Submit][Status ...
- BZOJ 2157 「国家集训队」旅游(树链剖分,线段树,边权转点权)【BZOJ计划】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2157 是 hydro 的 BZOJ ...
- 【树链剖分】旅游(luogu 3976)
正题 luogu 3976 题目大意 给你一棵树,每个点有一个权值s 现在给你一条路径,让你选择两个点x,y,使y在x后面,且sy−sxs_y-s_xsy−sx最大 然后该路劲上所有点权值加v 解 ...
- 【暖*墟】#树链剖分# 树链剖分学习与练习
树链剖分 树链剖分是一种优化,将树上最常经过的几条链划为重点,用线段树来优化区间修改和查询. 并且因为在一棵子树中dfs序是连续的,并且在任意一条重链上,dfs序也是连续的, 可以认为轻链是单点修改, ...
- 【ZJOI2008】树的统计(树链剖分)
传送门 Solution: 就是树链剖分入门题啦~ // luogu-judger-enable-o2 #include<bits/stdc++.h> #define N 30005 #d ...
- 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)
题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...
- 【模板】树链剖分 P3384
题目链接 //部分转自:https://www.luogu.org/problemnew/solution/P3384 初学树链剖分,感觉这个模板题还是容易理解的,但是实在是码量很大的. 知识点: 重 ...
最新文章
- 是时候转型 Serverless 来玩微服务了吗?
- 第六章勘误以及Normalization算法不完整
- SAP S/4HANA里KPI tile的一个具体例子
- VS2015 代码左缩进
- 计算机科学导论第五版_五月份将开始提供438项免费在线编程和计算机科学课程
- Spring Boot中使用@Async实现异步调用
- codeblocks如何让输出结果 空格_简单讲讲如何实现两个正整数相加,然后输出这个结果...
- 简历避免采坑总结——为什么你的简历杳无音信?程序员的简历该怎么写?看这一篇就够了!毕业生快进 (待更新)
- 日期的前端验证 jquery
- 5.11 学习日记,首页banner做好了
- php查询mongo数据库效率,2000000万数据库 MongoDB 查询速度慢
- 河南农业大学计算机试题,河南农业大学计算机vb考试必出
- android开发工具哪个好_小程序开发工具怎么用?哪个好用?
- 数据结构之二叉树--转载
- C# 简单封装一个XML文件读取类
- 精通javascript学习笔记
- 本地快速搭建FTP服务器
- CSDN格式字体颜色入门
- 【软件测试】黑盒测试方法小结
- [Ynoi2018]五彩斑斓的世界