题目链接

  不会换根从暑假开始就困扰我了……拖到现在……

  会了还是很激动的。

  换根操作事实上不需要(也不能)改树剖本来的dfs序……只是在query上动动手脚……

  设全树的集合为G,以root为根,u在原根到新根的链上的子树集合为G',则有查询区间=G-G'……

  然后查询的时候就查G-G'就行

  

#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<cstring>
#define left (rt<<1)
#define right (rt<<1|1)
#define mid ((l+r)>>1)
#define lson l,mid,left
#define rson mid+1,r,right
#define maxn 100020
using namespace std;
inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} struct Edge{
int next,to;
}edge[maxn*];
int head[maxn],num;
inline void add(int from,int to){
edge[++num]=(Edge){head[from],to};
head[from]=num;
} int tree[maxn*];
int tag[maxn*];
int size[maxn];
int deep[maxn];
int son[maxn];
int father[maxn];
int top[maxn];
int dfn[maxn];
int back[maxn],ID;
int q[maxn];
int s[maxn][];
int n,m; void find(int x,int fa){
deep[x]=deep[fa]+; size[x]=;
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(to==fa) continue;
father[to]=x;
s[to][]=x;
find(to,x);
size[x]+=size[to];
if(son[x]==||size[son[x]]<size[to]) son[x]=to;
}
} void unionn(int x,int Top){
dfn[x]=++ID; back[ID]=x;
top[x]=Top;
if(!son[x]) return;
unionn(son[x],Top);
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(to==father[x]||to==son[x]) continue;
unionn(to,to);
}
} inline void pushup(int rt){
tree[rt]=min(tree[left],tree[right]);
} void pushdown(int rt){
if(tag[rt]==-) return;
tag[left]=tag[right]=tag[rt];
tree[left]=tree[right]=tag[rt];
tag[rt]=-;
return;
} void build(int l,int r,int rt){
tag[rt]=-;
if(l==r){
tree[rt]=q[back[l]];
return;
}
build(lson);
build(rson);
pushup(rt);
} void memseg(int from,int to,int num,int l,int r,int rt){
if(from<=l&&to>=r){
tree[rt]=tag[rt]=num;
//printf("%d %d l=%d r=%d %d\n",from,to,l,r,num);
return;
}
pushdown(rt);
if(from<=mid) memseg(from,to,num,lson);
if(to>mid) memseg(from,to,num,rson);
pushup(rt);
return;
} int query(int from,int to,int l,int r,int rt){
if(from<=l&&to>=r) return tree[rt];
pushdown(rt);
int ans=0x7fffffff;
if(from<=mid) ans=min(ans,query(from,to,lson));
if(to>mid) ans=min(ans,query(from,to,rson));
return ans;
} int root; void update(int from,int to,int num){
while(top[from]!=top[to]){
if(deep[top[from]]<deep[top[to]]) swap(from,to);
memseg(dfn[top[from]],dfn[from],num,,n,);
from=father[top[from]];
}
if(deep[from]>deep[to]) swap(from,to);
memseg(dfn[from],dfn[to],num,,n,);
return;
} int LCA(int from,int to){
if(deep[from]<deep[to]) swap(from,to);
int f=deep[from]-deep[to];
for(int i=;(<<i)<=f;++i)
if(f&(<<i)) from=s[from][i];
if(from==to) return from;
for(int i=;i>=;--i){
if(s[from][i]==s[to][i]) continue;
from=s[from][i];
to=s[to][i];
}
return s[from][];
} inline void prepare(){
for(int j=;j<=;++j)
for(int i=;i<=n;++i) s[i][j]=s[s[i][j-]][j-];
} int ask(int o){
if(root==) return query(dfn[o],dfn[o]+size[o]-,,n,);
int lca=LCA(root,o);
if(lca!=o) return query(dfn[o],dfn[o]+size[o]-,,n,);
else{
int now=root;
for(int i=;i>=;--i)
if(deep[s[now][i]]>deep[o]) now=s[now][i];
int ans=0x7fffffff;
if(dfn[now]>) ans=min(ans,query(,dfn[now]-,,n,));
if(dfn[now]+size[now]<=n) ans=min(ans,query(dfn[now]+size[now],n,,n,));
return ans;
}
} int main(){
n=read(),m=read();
for(int i=;i<n;++i){
int from=read(),to=read();
add(from,to);
add(to,from);
}
for(int i=;i<=n;++i) q[i]=read();
root=read();
find(,);
unionn(,);
build(,n,);
prepare();
for(int i=;i<=m;++i){
int opt=read();
if(opt==) root=read();
else if(opt==){
int x=read(),y=read(),z=read();
update(x,y,z);
}
else{
int x=read();
printf("%d\n",ask(x));
}
}
return ;
}
/*
10 10
1 2
2 3
2 4
1 5
5 6
5 10
5 7
7 8
7 9
5 1 2 3 6 4 7 8 9 10
1
*/

  话说写博客超简略的我简直是业界毒瘤啊……

【Luogu】P3979遥远的国度(树链剖分)的更多相关文章

  1. 洛谷P3979 遥远的国度 树链剖分+分类讨论

    题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...

  2. [luogu P3384] [模板]树链剖分

    [luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...

  3. BZOJ 3083 遥远的国度 树链剖分

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 797  Solved: 181[Submit][Status] Descrip ...

  4. BZOJ 3083 遥远的国度(树链剖分+LCA)

    Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...

  5. 【bzoj3083】遥远的国度 树链剖分+线段树

    题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...

  6. BZOJ 3083: 遥远的国度(树链剖分+DFS序)

    可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...

  7. BZOJ 3083 遥远的国度 树链剖分+线段树

    有换根的树链剖分的裸题. 在换根的时候注意讨论. 注意数据范围要开unsigned int或longlong #include<iostream> #include<cstdio&g ...

  8. 【Luogu P3384】树链剖分模板

    树链剖分的基本思想是把一棵树剖分成若干条链,再利用线段树等数据结构维护相关数据,可以非常暴力优雅地解决很多问题. 树链剖分中的几个基本概念: 重儿子:对于当前节点的所有儿子中,子树大小最大的一个儿子就 ...

  9. BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 1280 MBSubmit: 3127  Solved: 795[Submit][Status][Discu ...

  10. luoguP3979 遥远的国度 树链剖分

    \(1, 2\)操作没什么好说的 对于\(3\)操作,分三种情况讨论下 \(id = rt\)的情况下,查整棵树的最小值即可 如果\(rt\)在\(1\)号点为根的情况下不在\(id\)的子树中,那么 ...

随机推荐

  1. python爬虫之路——对字符串的处理

    对字符串的处理分类:分段,连接,剔除,提取,综合 连接:+,* +(加法)的使用 a='i' b=' love' c=' you' print(a+b+c) #return i love you *( ...

  2. 使用ABAP批量下载有道云笔记中的图片

    Jerry喜欢用有道云笔记这款软件做自己的知识管理和知识体系的构建. 当您看到一篇好的有道云笔记分享时,可能会想将其精美的图片下载到本地.作为程序猿,我们不会去手动一张张下载.写个程序帮我们自动下载吧 ...

  3. 3. Netbackup 7.6客户端的安装(windows/linux)

    1 客户端的安装 1.1 Windows客户端安装 1.1.1 客户端hosts修改 windows xp/2003/vista/2008/7/8用户HOSTS文件是在“c:\windows\syst ...

  4. ArcGis server发布地图服务

    ArcGIS server发布服务: 首先修改地图文档属性中的关联默认数据库 最后使用分享将地图服务发布到server上,是地图服务可以使用: 注意一定要勾选 Feature Access选项 fea ...

  5. Spring boot 集成Kafka

    搭建Kafka集群,参考: https://www.cnblogs.com/jonban/p/kafka.html 源码示例如下: 1.新建 Maven 项目 kafka 2.pom.xml < ...

  6. 实验十三 团队作业9:Beta冲刺与团队项目验收

    实验十三 团队作业9:Beta冲刺与团队项目验收 实验时间 2019-6-20(21) Deadline: [6.20-6.26]之间任选连续3天的23:00,以团队随笔博文提交时间为准. 评分标准: ...

  7. 谈谈TCP的四次挥手

    “挥手”是为了终止连接,TCP四次挥手的流程图如下: (在socket编程中,可以由客户端或服务端进行close操作来进行) 下面的图是由客户端主动关闭连接 MSL是什么?最长报文段寿命 ------ ...

  8. 《剑指offer》51:数组中的逆序对

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...

  9. bootstrap 警告(Alerts)

    本章将讲解警告(Alerts)以及bootstrap所提供的用于警告的class类.警告(Alerts)向用户提供了一种定义消息样式的方式.它们为典型的用户操作提供了上下文信息反馈. 您可以为警告框添 ...

  10. cron job 里面,如何让脚本半分钟运行一次?

    cron job 里面,如何让脚本半分钟运行一次? cron本身实现不了.但可以借助于sleep命令实现. 解决方法: 两个脚本 一个正常,一个增加sleep 30 crontab设置同时启动 在有的 ...