洛谷P3979 遥远的国度 树链剖分+分类讨论
题意:给出一棵树,这棵树每个点有权值,然后有3种操作。操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值。
解法:如果没有修改树根操作那么这题就是树链剖分的裸题。但是修改树根操作会使得题目变得复杂一些,这里直接说结论:我们先直接以1为根建树进行树链剖分,这样的话根固定了那么路径修改操作就照常,然后我们要考虑换根操作对查询的影响(这是重点)。
画图分析后可以发现,可以分为3种情况,①x==rt,询问的就是整棵树 ②x不在1到rt的路径上,对查询没有影响,查询照常 3 x在1到rt的路径上,这样会麻烦一些,仔细观察图发现其实查询就变成了查询除去(x的rt所在的子树)那么我们就可以先用倍增找到(x的rt所在的子树)这颗子树的根为 y=rt的dep[rt]-dep[x]-1级祖先。这样查询除去y的子树剩下的左右两个区间合并就是答案了。
这道题还是很不错的,做了能涨处理这样的换根问题的姿势。
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long LL;
- const LL INF=1LL<<;
- const int N=1e5+;
- int n,m,T,rt,num=,f[N][];
- LL v[N];
- struct node{
- int dep,fa,sz,heavy;
- int toseg,top; LL val;
- }tree[N]; //原本的树
- int totree[N<<]; //线段树点i代表原树的点totree[i]
- /*-------------------------以下为线段树-----------------------------*/
- LL Min[N<<],tag[N<<];
- void pushdown(int rt) {
- if (!tag[rt]) return;
- Min[rt<<]=tag[rt<<]=tag[rt];
- Min[rt<<|]=tag[rt<<|]=tag[rt];
- tag[rt]=;
- }
- void pushup(int rt) {
- Min[rt]=min(Min[rt<<],Min[rt<<|]);
- }
- void build(int rt,int l,int r) {
- if (l==r) {
- Min[rt]=tree[totree[l]].val; tag[rt]=;
- return;
- }
- int mid=l+r>>;
- build(rt<<,l,mid);
- build(rt<<|,mid+,r);
- pushup(rt);
- }
- void update(int rt,int l,int r,int ql,int qr,LL v) {
- if (ql<=l && r<=qr) {
- Min[rt]=tag[rt]=v;
- return;
- }
- int mid=l+r>>;
- pushdown(rt);
- if (ql<=mid) update(rt<<,l,mid,ql,qr,v);
- if (qr>mid) update(rt<<|,mid+,r,ql,qr,v);
- pushup(rt);
- }
- LL query(int rt,int l,int r,int ql,int qr) {
- if (ql<=l && r<=qr) return Min[rt];
- int mid=l+r>>; LL ret=INF;
- pushdown(rt);
- if (ql<=mid) ret=min(ret,query(rt<<,l,mid,ql,qr));
- if (qr>mid) ret=min(ret,query(rt<<|,mid+,r,ql,qr));
- return ret;
- }
- /*--------------------------以下为树链剖分----------------------------*/
- int cnt=,head[N<<],to[N<<],nxt[N<<];
- void add_edge(int x,int y) {
- nxt[++cnt]=head[x]; to[cnt]=y; head[x]=cnt;
- }
- void dfs1(int x,int fa,int dep) { //点x的父亲为fa深度为dep
- tree[x].dep=dep;
- tree[x].fa=fa;
- tree[x].sz=;
- tree[x].val=v[x];
- int maxson=-;
- for (int i=head[x];i;i=nxt[i]) {
- int y=to[i];
- if (y==fa) continue;
- f[y][]=x; //在dfs1的时候顺便求倍增数组
- for (int j=;j<=T;j++)
- f[y][j]=f[f[y][j-]][j-];
- dfs1(y,x,dep+);
- tree[x].sz+=tree[y].sz;
- if (tree[y].sz>maxson) tree[x].heavy=y,maxson=tree[y].sz;
- }
- }
- void dfs2(int x,int top) { //点x所在树链的top
- tree[x].toseg=++num;
- tree[x].top=top;
- totree[num]=x;
- if (!tree[x].heavy) return; //叶子结点
- dfs2(tree[x].heavy,top); //先剖分重儿子
- for (int i=head[x];i;i=nxt[i]) { //再剖分轻儿子
- int y=to[i];
- if (y==tree[x].fa || y==tree[x].heavy) continue;
- dfs2(y,y);
- }
- }
- void update2(int x,int y,LL z) { //修改x到y路径的值
- while (tree[x].top!=tree[y].top) { //不在同一条链上
- if (tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y); //x为深度大的链
- update(,,n,tree[tree[x].top].toseg,tree[x].toseg,z); //x向上跳的同时更新
- x=tree[tree[x].top].fa; //深度大的向上跳
- }
- if (tree[x].dep>tree[y].dep) swap(x,y); //这里x和y在同一条链
- update(,,n,tree[x].toseg,tree[y].toseg,z); //x和y这条链的更新
- }
- int getfa(int x,int k) { //取得x的k级祖先
- if (k<) return -;
- for (int i=T;i>=;i--)
- if (k>=(<<i)) x=f[x][i],k-=(<<i);
- return x;
- }
- int main()
- {
- cin>>n>>m;
- T=(int)log2(n)+;
- for (int i=;i<n;i++) {
- int x,y; scanf("%d%d",&x,&y);
- add_edge(x,y); add_edge(y,x);
- }
- for (int i=;i<=n;i++) scanf("%lld",&v[i]);
- dfs1(,,);
- dfs2(,);
- build(,,n);
- scanf("%d",&rt);
- for (int i=;i<=m;i++) {
- LL opt,x,y,z; scanf("%lld",&opt);
- if (opt==) {
- scanf("%d",&rt);
- }
- if (opt==) {
- scanf("%lld%lld%lld",&x,&y,&z);
- update2(x,y,z);
- }
- if (opt==) {
- scanf("%lld",&x);
- if (x==rt) printf("%lld\n",query(,,n,,n)); //x就是root
- else if (x==getfa(rt,tree[rt].dep-tree[x].dep)) { //x在1到root的路径上
- y=getfa(rt,tree[rt].dep-tree[x].dep-); //取得去掉部分的根(这要画图理解)
- z=INF;
- if (tree[y].toseg->=) z=min(z,query(,,n,,tree[y].toseg-));
- if (tree[y].toseg+tree[y].sz<=n) z=min(z,query(,,n,tree[y].toseg+tree[y].sz,n));
- printf("%lld\n",z);
- } else { //其他情况,直接查询子树
- printf("%lld\n",query(,,n,tree[x].toseg,tree[x].toseg+tree[x].sz-));
- }
- }
- }
- return ;
- }
洛谷P3979 遥远的国度 树链剖分+分类讨论的更多相关文章
- 洛谷 P4114 Qtree1 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例: 输出样例: 说明 说明 思路 Change Query AC代码 总结 题面 题目链接 P4114 Qt ...
- [洛谷P3384] [模板] 树链剖分
题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...
- 洛谷.4114.Qtree1(树链剖分)
题目链接 模板题都错了这么多次.. //边权赋到点上 树剖模板 //注意LCA.链的顶端不能统计到答案! #include <cstdio> #include <cctype> ...
- 洛谷3384&bzoj1036树链剖分
值得注意的是: 一个点的子树是存在一起的...也就是说我们修改子树的时候只用... /********************************************************* ...
- BZOJ 3083 遥远的国度 树链剖分
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 797 Solved: 181[Submit][Status] Descrip ...
- BZOJ 3083 遥远的国度(树链剖分+LCA)
Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...
- 【bzoj3083】遥远的国度 树链剖分+线段树
题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...
- BZOJ 3083: 遥远的国度(树链剖分+DFS序)
可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...
- BZOJ 3083 遥远的国度 树链剖分+线段树
有换根的树链剖分的裸题. 在换根的时候注意讨论. 注意数据范围要开unsigned int或longlong #include<iostream> #include<cstdio&g ...
随机推荐
- AJAX 步骤分析
HTML 步骤: 1. 创建异步对象 2. 设置请求行 3. 设置请求头(get请求可以省略) 4. 注册状态改变事件 4.1. 判断状态&请求是否成功并使用数据 5. 发送请求 PH ...
- 深入Spring:自定义IOC
前言 上一篇文章讲了如何自定义注解,注解的加载和使用,这篇讲一下Spring的IOC过程,并通过自定义注解来实现IOC. 自定义注解 还是先看一下个最简单的例子,源码同样放在了Github. 先定义自 ...
- wxDateTime用法和转换成wxString
转载别人的.void datetest() { wxDateTime now=wxDateTime::Now(); wxString date1=now.Format(); wxString date ...
- Linux 下安装sql server 时 2G内存限制的最新(2019-08-15) 解决方案
关于 sqlserver 在linux下安装时有最小内存限制的问题,网上有很多类似的说明,那些操作都是正确的,如果不成功可能 “姿势”不对. 需要注意的是:不能使用最新版本!!! 不能在线下载!!! ...
- Spring MVC 配置Controller详解
在SpringMVC中,对于Controller的配置方式有很多种,如下做简单总结 第一种 URL对应Bean如果要使用此类配置方式,需要在XML中做如下样式配置: <!-- 表示将请求的URL ...
- excel导出简单示例(jxl jar包)
@param title excel文件名 @param excelTopName 表头中文名字(显示在第一行的中文表头内容) @param header 表头字段属性(根据该属性获取对应的属性值,表 ...
- Bootstrap 网页2
html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <me ...
- Jenkins配置定时构建项目
general: 源码管理: 构建触发器: 构建后操作:
- Linux eth0, eth1, ..., eth%d 的生成【转】
转自:https://blog.csdn.net/xiruanliuwei/article/details/78765255 一直很好奇,Linux下的eth0, eth1,eth2等是如何生成的~ ...
- UNP学习第七章
一.套接口选项 函数getsockopt和setsockopt 函数fcntl 函数ioctl 二.getsockopt和setsockopt函数 #include <sys/socket.h& ...