首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区间,后者询问区间的补集。

/**************************************************************
Problem: 3083
User: BLADEVIL
Language: C++
Result: Accepted
Time:6412 ms
Memory:43904 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 200010
#define maxm 400010
#define inf (~0U>>1) using namespace std; struct segment_tree {
int left,right,min_,lazy;
}t[maxn<<]; int n,m,l,rot,tot;
int key[maxn];
int other[maxm],pre[maxm],last[maxn];
int size[maxn],max_son[maxn],top[maxn],dep[maxn],a[maxn],num[maxn][],jump[maxn][],dis[maxn]; void connect(int x,int y) {
pre[++l]=last[x];
last[x]=l;
other[l]=y;
} void update(int x) {
t[x].min_=min(t[x<<].min_,t[(x<<)+].min_);
} void push_down(int x) {
t[x<<].lazy=t[(x<<)+].lazy=t[x].lazy;
t[x<<].min_=t[(x<<)+].min_=t[x].min_;
t[x].lazy=;
} int get_lca(int x,int y) {
if (dis[x]>dis[y]) swap(x,y);
int det=dis[y]-dis[x];
for (int j=;j<=;j++) if (det&(<<j)) y=jump[y][j];
if (x==y) return x;
for (int j=;j>=;j--)
if (jump[x][j]!=jump[y][j]) x=jump[x][j],y=jump[y][j];
return jump[x][];
} int get_lca_son(int x,int y) {
if (dis[x]>dis[y]) swap(x,y);
for (int j=;j>=;j--)
if (dis[jump[y][j]]>dis[x]) y=jump[y][j];
return y;
} void dfs(int x) {
size[x]=;
for (int p=last[x];p;p=pre[p]) {
if (dis[other[p]]) continue;
jump[other[p]][]=x; dis[other[p]]=dis[x]+;
dfs(other[p]);
size[x]+=size[other[p]];
if (size[other[p]]>size[max_son[x]]) max_son[x]=other[p];
}
} void make_segment(int x) {
num[x][]=++tot; a[tot]=key[x];
if (max_son[x]) {
top[max_son[x]]=top[x];
dep[max_son[x]]=dep[x];
make_segment(max_son[x]);
}
for (int p=last[x];p;p=pre[p]) {
if (other[p]==jump[x][]) continue;
if (other[p]==max_son[x]) continue;
top[other[p]]=other[p];
dep[other[p]]=dep[x]+;
make_segment(other[p]);
}
num[x][]=tot;
} void build_segment(int x,int l,int r) {
t[x].left=l; t[x].right=r;
if (t[x].left==t[x].right) {
t[x].min_=a[t[x].left];
return ;
}
int mid=t[x].left+t[x].right>>;
build_segment(x<<,l,mid); build_segment((x<<)+,mid+,r);
update(x);
} void change_segment_tree(int x,int l,int r,int y) {
if (t[x].lazy) push_down(x);
if ((t[x].left==l)&&(t[x].right==r)) {
t[x].lazy=t[x].min_=y;
return ;
}
int mid=t[x].left+t[x].right>>;
if (l>mid) change_segment_tree((x<<)+,l,r,y); else
if (r<=mid) change_segment_tree(x<<,l,r,y); else
change_segment_tree(x<<,l,mid,y),change_segment_tree((x<<)+,mid+,r,y);
update(x);
} void change(int x,int y,int z) {
if (dep[x]>dep[y]) swap(x,y);
while (dep[x]!=dep[y]) {
change_segment_tree(,num[top[y]][],num[y][],z);
y=jump[top[y]][];
}
while (top[x]!=top[y]) {
change_segment_tree(,num[top[x]][],num[x][],z);
change_segment_tree(,num[top[y]][],num[y][],z);
x=jump[top[x]][];
y=jump[top[y]][];
}
if (num[x][]>num[y][]) swap(x,y);
change_segment_tree(,num[x][],num[y][],z);
} int query_segment_tree(int x,int l,int r) {
if (l>r) return inf;
if (t[x].lazy) push_down(x);
if ((t[x].left==l)&&(t[x].right==r)) return t[x].min_;
int mid=t[x].left+t[x].right>>;
if (l>mid) return query_segment_tree((x<<)+,l,r); else
if (r<=mid) return query_segment_tree(x<<,l,r); else
return min(query_segment_tree(x<<,l,mid),query_segment_tree((x<<)+,mid+,r));
} void query(int x) {
if (x==rot) {
printf("%d\n",t[].min_);
return ;
}
if (get_lca(x,rot)!=x) printf("%d\n",query_segment_tree(,num[x][],num[x][])); else {
int y=get_lca_son(x,rot);
printf("%d\n",min(query_segment_tree(,,num[y][]-),query_segment_tree(,num[y][]+,n)));
//printf("%d %d\n",query_segment_tree(1,1,num[y][0]-1),query_segment_tree(1,num[y][1]+1,n));
//printf("%d\n",y);
//printf("%d %d\n",num[y][0],num[y][1]);
}
} int main() {
//freopen("country.in","r",stdin); freopen("country.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
connect(x,y); connect(y,x);
}
for (int i=;i<=n;i++) scanf("%d",&key[i]);
scanf("%d",&rot);
dis[rot]=;
dfs(rot);
top[rot]=rot; dep[rot]=;
make_segment(rot);
//for (int i=1;i<=n;i++) printf("%d %d %d %d %d\n",i,max_son[i],size[i],num[i][0],num[i][1]);
build_segment(,,n);
for (int j=;j<=;j++)
for (int i=;i<=n;i++) jump[i][j]=jump[jump[i][j-]][j-];
while (m--) {
int opt; scanf("%d",&opt);
if (opt==) scanf("%d",&rot); else
if (opt==) {
int l,r,y; scanf("%d%d%d",&l,&r,&y);
change(l,r,y);
} else {
int x; scanf("%d",&x);
query(x);
}
}
return ;
}

bzoj 3083 树链剖分的更多相关文章

  1. BZOJ 3083 树链剖分+倍增+线段树

    思路: 先随便选个点 链剖+线段树 1操作 就直接改root变量的值 2操作 线段树上改 3操作 分成三种情况 1.new root = xx 整个子树的min就是ans 2. lca(new roo ...

  2. BZOJ 4326 树链剖分+二分+差分+记忆化

    去年NOIP的时候我还不会树链剖分! 还是被UOJ 的数据卡了一组. 差分的思想还是很神啊! #include <iostream> #include <cstring> #i ...

  3. BZOJ 1036 && 树链剖分

    还是太弱啊..各种数据结构只听过名字却没有一点概念..树链剖分也在这个范畴..今天来进一步深化一下教育改革推进全民素质提高. 性质 忘了在哪里看到的一篇blog有一句话讲得非常好,树链剖分不是一种数据 ...

  4. bzoj 2243 树链剖分

    2013-11-19 16:21 原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分,用线段树记录该区间的颜色段数,左右端点颜 ...

  5. bzoj 4196 树链剖分 模板

    [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2135  Solved: 1232[Submit][Status][D ...

  6. BZOJ 4811 树链剖分+线段树

    思路: 感觉这题也可神了.. (还是我太弱) 首先发现每一位不会互相影响,可以把每一位分开考虑,然后用树链剖分或者LCT维护这个树 修改直接修改,询问的时候算出来每一位填0,1经过这条链的变换之后得到 ...

  7. BZOJ 4034 树链剖分

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4034 题意:中文题面 思路:树链剖分入门题. 剖分后就是一个简单的区间更新和区间求和问题. ...

  8. BZOJ 2286 树链剖分+DFS序+虚树+树形DP

    第一次学习虚树,就是把无关的点去掉.S里维护一条链即可. #include <iostream> #include <cstring> #include <cstdio& ...

  9. BZOJ 2836 树链剖分+线段树

    思路: 链剖+线段树裸题 重链的标号就是DFS序 所以查子树的时候每回就 query(change[x],change[x]+size[x]-1) 就好了 剩下的应该都会吧.. //By Sirius ...

随机推荐

  1. 利用Docker安装Web前端性能测试工具Sitespeed.io

    目录结构 一.Sitespeed.io概述 1.Sitespeed.io简介 2.Sitespeed.io使用场景 二.Sitespeed.io的安装和使用 1.安装Sitespeed.io 2.连接 ...

  2. 用Python实现求Fibonacci数列的第n项

    1. 背景——Fabonacci数列的介绍(摘自百度百科): 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacc ...

  3. windows远程连接设置

    1.设置整个服务器只允许一个连接. 使用组策略管理gpedit.msc, 计算机配置>管理模板>windows组件 >终端服务>限制连接数量,设为已启动,数量设置为1. 此设置 ...

  4. 在MFC中显示cmd命令行

    添加函数 void InitConsoleWindow1() { ; FILE* fp; AllocConsole(); nCrt = _open_osfhandle((long)GetStdHand ...

  5. 第190天:js---String常用属性和方法(最全)

    String常用属性和方法 一.string对象构造函数 /*string对象构造函数*/ console.log('字符串即对象');//字符串即对象 //传统方式 - 背后会自动将其转换成对象 / ...

  6. UVA12583_Memory Overow

    题目是很简单的队列维护的题目. 每次加入之前判断该字母是否在队列以及队列的容量是否超过k即可. #include <iostream> #include <cstdio> #i ...

  7. BZOJ 2004 公交线路(状压DP+矩阵快速幂)

    注意到每个路线相邻车站的距离不超过K,也就是说我们可以对连续K个车站的状态进行状压. 然后状压DP一下,用矩阵快速幂加速运算即可. #include <stdio.h> #include ...

  8. 题解 P1478 【陶陶摘苹果(升级版)】

    看着你们累死累活得快排.冒泡.结构体特殊冒泡.还有dp... 蒟蒻表示真的不用那么麻烦! 难度:新手村+1 压行情况:0 理解难度:0 首先我们来了解一下优先队列:(自己抄的自己...) 讲元素一个个 ...

  9. 【刷题】BZOJ 4349 最小树形图

    Description 小C现在正要攻打科学馆腹地------计算机第三机房.而信息组的同学们已经建好了一座座堡垒,准备迎战.小C作为一种高度智慧的可怕生物,早已对同学们的信息了如指掌. 攻打每一个人 ...

  10. 【刷题】LOJ 6038 「雅礼集训 2017 Day5」远行

    题目描述 Miranda 生活的城市有 \(N\) 个小镇,一开始小镇间没有任何道路连接.随着经济发现,小镇之间陆续建起了一些双向的道路但是由于经济不太发达,在建设过程中,会保证对于任意两个小镇,最多 ...