传送门

解题思路

  前两个操作都比较基础。对于第三个操作分类讨论一下,首先如果当前根不是要操作点的子树,那么就无影响,直接查询操作点的子树即可。第二种是当前根是操作点的子树,那就找到当前根到操作点这条链的顶端(也就是操作点的儿子,这个儿子为当前根的祖先),然后将这块连续的\(dfs\)序挖掉,查询两边就行了。找这个点的时候用倍增即可。(暴力往上跳也能过)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib> using namespace std;
const int MAXN = 100005; inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
} int n,m,head[MAXN],cnt,to[MAXN<<1],nxt[MAXN<<1],w[MAXN],wt[MAXN],rt,num,g[MAXN][20];
int siz[MAXN],fa[MAXN],son[MAXN],id[MAXN],Min[MAXN<<2],tag[MAXN<<2],top[MAXN],dep[MAXN]; inline int min(int x,int y){
return x<y?x:y;
} inline void add(int bg,int ed){
to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
} void dfs1(int x,int f,int d){
dep[x]=d;fa[x]=f;siz[x]=1;g[x][0]=f;
for(int i=1;i<=18;i++) g[x][i]=g[g[x][i-1]][i-1];
int maxson=-1,u;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==f) continue;
dfs1(u,x,d+1);siz[x]+=siz[u];
if(siz[u]>maxson) {maxson=siz[u];son[x]=u;}
}
} void dfs2(int x,int topf){
id[x]=++num;wt[num]=w[x];
top[x]=topf;if(!son[x]) return;
dfs2(son[x],topf);int u;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==fa[x] || u==son[x]) continue;
dfs2(u,u);
}
} void build(int x,int l,int r){
if(l==r) {Min[x]=wt[l];return;}
int mid=(l+r)>>1;
build(x<<1,l,mid);build(x<<1|1,mid+1,r);
Min[x]=min(Min[x<<1],Min[x<<1|1]);
} inline void pushdown(int x){
Min[x<<1]=tag[x];Min[x<<1|1]=tag[x];
tag[x<<1]=tag[x];tag[x<<1|1]=tag[x];
tag[x]=0;
} void update(int x,int l,int r,int L,int R,int k){
if(L<=l && r<=R) {Min[x]=k;tag[x]=k;return;}
int mid=(l+r)>>1;if(tag[x]) pushdown(x);
if(L<=mid) update(x<<1,l,mid,L,R,k);
if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
Min[x]=min(Min[x<<1],Min[x<<1|1]);
} int query(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return Min[x];
int mid=(l+r)>>1,ret=0x7fffffff;if(tag[x]) pushdown(x);
if(L<=mid) ret=min(ret,query(x<<1,l,mid,L,R));
if(mid<R) ret=min(ret,query(x<<1|1,mid+1,r,L,R));
return ret;
} inline void updRange(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],k);x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);update(1,1,n,id[x],id[y],k);
} inline int qRange(int x,int y){
if(fa[x]==y) return x;
for(int i=18;i>=0;i--){
if(fa[g[x][i]]==y) return g[x][i];
if(dep[fa[g[x][i]]]>dep[y]) x=g[x][i];
}
return x;
} inline int qSon(int x){
if(x==rt) return query(1,1,n,1,n);
if(id[rt]>id[x]+siz[x]-1 || id[rt]<id[x]) return query(1,1,n,id[x],id[x]+siz[x]-1);
int point=qRange(rt,x),ret=0x7fffffff;
if(id[point]+siz[point]<=n) ret=min(ret,query(1,1,n,id[point]+siz[point],n));
if(id[point]-1>=1) ret=min(ret,query(1,1,n,1,id[point]-1));return ret;
} int main(){
n=rd(),m=rd();int x,y,op,z;
for(int i=1;i<n;i++){
x=rd(),y=rd();
add(x,y),add(y,x);
}
for(int i=1;i<=n;i++) w[i]=rd();rt=rd();
dfs1(rt,0,1);dfs2(rt,rt);build(1,1,n);
while(m--){
op=rd();
if(op==1) x=rd(),rt=x;
if(op==2){
x=rd(),y=rd(),z=rd();
updRange(x,y,z);
}
if(op==3) {x=rd();printf("%d\n",qSon(x));}
}
return 0;
}

BZOJ 3083: 遥远的国度 (树剖+线段树)的更多相关文章

  1. BZOJ_2238_Mst_树剖+线段树

    BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...

  2. BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树

    BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...

  3. BZOJ_2157_旅游_树剖+线段树

    BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...

  4. 【BZOJ5210】最大连通子块和 树剖线段树+动态DP

    [BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...

  5. [LNOI2014]LCA(树剖+线段树)

    \(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...

  6. [CF1007D]Ants[2-SAT+树剖+线段树优化建图]

    题意 我们用路径 \((u, v)\) 表示一棵树上从结点 \(u\) 到结点 \(v\) 的最短路径. 给定一棵由 \(n\) 个结点构成的树.你需要用 \(m\) 种不同的颜色为这棵树的树边染色, ...

  7. LOJ#3088. 「GXOI / GZOI2019」旧词(树剖+线段树)

    题面 传送门 题解 先考虑\(k=1\)的情况,我们可以离线处理,从小到大对于每一个\(i\),令\(1\)到\(i\)的路径上每个节点权值增加\(1\),然后对于所有\(x=i\)的询问查一下\(y ...

  8. BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)

    传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...

  9. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

  10. POJ3237 Tree(树剖+线段树+lazy标记)

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

随机推荐

  1. Java中的API

    待施工 111 API: Scanner Random String StringBuilder ArrayList 集合详解: 包 import java.util.ArrayList 构造方法pu ...

  2. php操作redis--字符串篇

    前提:已经安装好了redis和相关拓展 常用函数:set/get/decr/incr等 应用场景:普遍的key/value存储类型 连接: $redis = new Redis(); $redis-& ...

  3. C/C++ fgets

    {     str_normalize_init();    unsigned options = SNO_TO_LOWER | SNO_TO_HALF;    if (argc > 1)    ...

  4. noip2015 提高组 day1t1 神奇的幻方

    题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,--,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...

  5. 兼容软件,Wine安装,Crossover安装,

    EL6 (RHEL6 and SL6) Required packages for proper building of 32-bit Wine on 64-bit EL6 yum install - ...

  6. HTTPS 加密原理探究

    由于之前项目中IOS系统建议将http协议换成https协议所以查看相关资料在此记录 HTTPS 通讯过程的基本原理 问:Https是什么? 答: HTTP 协议定义了一套规范,让客户端或浏览器可以和 ...

  7. Win7下使用DbgPrint

    在Win7下默认DbgPrint输出信息后,使用DbgView看不到内容. 新建一个reg文件,双击导出就行了. Windows Registry Editor Version 5.00 [HKEY_ ...

  8. C++之手写strlen函数

    代码: int strlen(const char *str){ assert(str!=NULL); intlen=; while((*str++)!='\0') len++; return len ...

  9. python 多设备同时安装app包

    python  多设备同时安装app包 上代码 #!/usr/bin/env python # -*- encoding: utf-8 -*- import os import time from m ...

  10. python3使用requests和requests_toolbelt上传文件

    https://blog.csdn.net/summerpowerz/article/details/80293235 https://blog.csdn.net/lhh08hasee/article ...