2018.06.30 BZOJ3083: 遥远的国度(换根树剖)
3083: 遥远的国度
Time Limit: 10 Sec Memory Limit: 512 MB
Description
描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。
Input
第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。
Output
对于每个opt=3的操作,输出一行代表对应子树的最小点权值。
Sample Input
3 7
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1
Sample Output
1
2
3
4
提示
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。
HINT
Source
zhonghaoxi提供
这题如果没有操作111就是一个裸的树链剖分:操作222路径修改,操作333维护子树最小值。
那么在加入了操作111之后,操作222的部分显然没有发生变化
代码:
inline void change(int x,int y,long long v){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,num[top[x]],num[x],v);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
update(1,num[y],num[x],v);
}
其中updateupdateupdate是指线段树的区间修改操作,numnumnum数组记录dfsdfsdfs序。
所以我们只需要考虑换根对维护子树最小值信息的影响,那么我们可以分类讨论一波:
我们设当前询问的子树的根为uuu,当前的根节点为rootrootroot。
第一种情况:lcalcalca(uuu,rootrootroot)!=uuu,那么我们发现在以rootrootroot为根时uuu原来的子树就是现在的子树,直接线段树区间查询。
第二种情况:uuu==rootrootroot,那么此时uuu就是根节点,直接返回线段树根节点的minminmin值
第三种情况:rootrootroot在uuu原来的子树内,即lcalcalca(rootrootroot,uuu)==uuu&&uuu!=rootrootroot,怎么做呢?
我们找到uuu在rootrootroot->uuu这条链上uuu的儿子sss,那么子树sss的补集就是我们查询的区间。
没有其他情况了
贴一发代码
#include<bits/stdc++.h>
#define N 100005
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
inline long long read(){
long long ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
return ans;
}
struct Node{int l,r;long long minn,lz;}T[N<<2];
struct node{int v,next;}e[N<<1];
long long a[N];
int first[N],dep[N],top[N],fa[N],hson[N],siz[N],num[N],pred[N],root,n,m,cnt=0,tot=0;
inline void add(int u,int v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;}
inline void dfs1(int p){
siz[p]=1,hson[p]=0;
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v==fa[p])continue;
fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
if(siz[v]>siz[hson[p]])hson[p]=v;
}
}
inline void dfs2(int p,int tp){
top[p]=tp,num[p]=++tot,pred[tot]=p;
if(hson[p])dfs2(hson[p],tp);
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v!=fa[p]&&v!=hson[p])dfs2(v,v);
}
}
inline long long min(long long a,long long b){return a<b?a:b;}
inline void pushup(int p){T[p].minn=min(T[lc].minn,T[rc].minn);}
inline void pushnow(int p,long long v){T[p].minn=v,T[p].lz=v;}
inline void pushdown(int p){
if(T[p].lz==0)return;
pushnow(lc,T[p].lz),pushnow(rc,T[p].lz),T[p].lz=0;
}
inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r,T[p].lz=0;
if(l==r){T[p].minn=a[pred[l]];return;}
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p);
}
inline void update(int p,int ql,int qr,long long v){
if(T[p].l>qr||T[p].r<ql)return;
if(ql<=T[p].l&&T[p].r<=qr){pushnow(p,v);return;}
pushdown(p);
if(qr<=mid)update(lc,ql,qr,v);
else if(ql>mid)update(rc,ql,qr,v);
else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
pushup(p);
}
inline long long query(int p,int ql,int qr){
if(T[p].l>qr||T[p].r<ql)return 1e16;
if(ql<=T[p].l&&T[p].r<=qr)return T[p].minn;
pushdown(p);
if(qr<=mid)return query(lc,ql,qr);
if(ql>mid)return query(rc,ql,qr);
return min(query(lc,ql,mid),query(rc,mid+1,qr));
}
inline void change(int x,int y,long long v){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,num[top[x]],num[x],v);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
update(1,num[y],num[x],v);
}
inline int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
inline int fid(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
if(fa[top[x]]==y)return top[x];
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
return hson[y];
}
int main(){
n=read(),m=read();
for(int i=1;i<n;++i){
int u=read(),v=read();
add(u,v),add(v,u);
}
for(int i=1;i<=n;++i)a[i]=read();
root=read();
dfs1(root);
dfs2(root,root);
build(1,1,n);
while(m--){
int op=read(),u=read();
if(op==1){root=u;continue;}
if(op==2){int v=read();long long w=read();change(u,v,w);continue;}
if(u==root){printf("%lld\n",T[1].minn);continue;}
int t=lca(u,root);
if(t!=u){printf("%lld\n",query(1,num[u],num[u]+siz[u]-1));continue;}
int s=fid(u,root);
printf("%lld\n",min(query(1,1,num[s]-1),query(1,num[s]+siz[s],n)));
}
return 0;
}
2018.06.30 BZOJ3083: 遥远的国度(换根树剖)的更多相关文章
- 2018.10.30 NOIP训练 【模板】树链剖分(换根树剖)
传送门 纯粹是为了熟悉板子. 然后发现自己手生了足足写了差不多25min而且输出的时候因为没开long longWA了三次还不知所云 代码
- 51nod1812树的双直径(换根树DP)
传送门:http://www.51nod.com/Challenge/Problem.html#!#problemId=1812 题解:头一次写换根树DP. 求两条不相交的直径乘积最大,所以可以这样考 ...
- 2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)
4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MB Description "奋战三星期,造台计算机".小G响应号召,花了三小时 ...
- 2018.06.30 BZOJ 3932: [CQOI2015]任务查询系统(主席树)
3932: [CQOI2015]任务查询系统 Time Limit: 20 Sec Memory Limit: 512 MB Description 最近实验室正在为其管理的超级计算机编制一套任务管理 ...
- 2018.09.30 bzoj4025: 二分图(线段树分治+并查集)
传送门 线段树分治好题. 这道题实际上有很多不同的做法: cdq分治. lct. - 而我学习了dzyo的线段树分治+并查集写法. 所谓线段树分治就是先把操作分成lognlognlogn个连续不相交的 ...
- 2018.06.30 cdq分治
#cdq分治 ##一种奇妙的分治方法 优点:可以顶替复杂的高级数据结构:常数比较小. 缺点:必须离线操作. CDQ分治的基本思想十分简单.如下: 我们要解决一系列问题,包含修改和查询操作,我们将这些问 ...
- 2018.06.30 BZOJ4443: [Scoi2015]小凸玩矩阵(二分加二分图匹配)
4443: [Scoi2015]小凸玩矩阵 Time Limit: 10 Sec Memory Limit: 128 MB Description 小凸和小方是好朋友,小方给小凸一个N*M(N< ...
- 2018.06.30 BZOJ1857: [Scoi2010]传送带(三分套三分)
1857: [Scoi2010]传送带 Time Limit: 1 Sec Memory Limit: 64 MB Description 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段 ...
- 2018.06.30 BZOJ1026: [SCOI2009]windy数(数位dp)
1026: [SCOI2009]windy数 Time Limit: 1 Sec Memory Limit: 162 MB Description windy定义了一种windy数.不含前导零且相邻两 ...
随机推荐
- leetcode50
public class Solution { public double MyPow(double x, int n) { return Math.Pow(x, (double)n); } }
- ajax 实现跨域
ajax本身是不可以跨域的,通过产生一个script标签来实现跨域.因为script标签的src属性是没有跨域的限制的. 其实设置了dataType: 'jsonp'后,$.ajax方法就和ajax ...
- Overcoming Life's Obstacles - ASC 2017 March 03-04
<Overcoming Life's Obstacles - How a top oboist overcame a neurological disorder to play again> ...
- 关于struts.xml配置文件的说明
<struts> <!-- action: 对应controller 中的类的 name: 匹配url要访问的类 class:包名+类名 通过反射产生对象 method:指定默认访问 ...
- conductor元数据定义
Task Definition conductor维护工作任务类型的注册表. 必须在工作流中使用之前注册任务类型. 例如: { "name": "encode_task& ...
- Spark之 Spark Streaming整合kafka(Java实现版本)
pom依赖 <properties> <scala.version>2.11.8</scala.version> <hadoop.version>2.7 ...
- tf.Session()、tf.InteractiveSession()
tf.Session()和tf.InteractiveSession()的区别 官方tutorial是这么说的: The only difference with a regular Session ...
- 37. Sudoku Solver (Array;Back-Track)
Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...
- MongoDB使用场景和局限 (转)
MongoDB的使用场景: 1.Web应用程序.文档能表示丰富的数据结构,建模相同数据库所需的集合数量通常会比使用完全正规化关系型数据库的数据表数量要少.动态查询和二级索引能让你轻松的实现SQL开发者 ...
- 25-javaweb接入支付宝支付接口
想熟悉支付宝接口支付,后面可能会用,不如在课设中试试手.好吧听说支付宝不微信支付要简单些,就拿支付宝的先练下手吧. 基本学习流程,百度一下,找篇博客看下. 推荐下面这个篇博客,讲的挺好的,复制过来. ...