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

/**************************************************************
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. jsonFormater之应用

        html代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...

  2. 西南大学校园网客户端共享网络之路由器开wifi

    1年前出了NetKeeper,让寝室只能一个人用一个账号,而且,在寝室平板手机什么的只能靠360wifi什么的来维持了,电脑一直不能关,确实让人不爽. 最近学校又出台了swu-wifi-dorm来让寝 ...

  3. 第132天:移动web端-rem布局(进阶)

    rem布局(进阶版) 该方案使用相当简单,把下面这段已压缩过的 原生JS(仅1kb,源码已在文章底部更新,2017/5/3) 放到 HTML 的 head 标签中即可(注:不要手动设置viewport ...

  4. python打印各种三角形

    # 打印左下角三角形:for i in range(10):之后,range(0,i)# 打印右上角三角形:在左下角的基础上,将"-"变成" "空格 for i ...

  5. C++解析(1):C到C++的升级

    0.目录 1.C与C++的关系 2.C到C++的升级 2.1 语言的实用性 2.2 register关键字 2.3 同名的全局变量 2.4 struct关键字 2.5 int f() 与 int f( ...

  6. StringUtils工具类说明

    /***************************************为空判断***************************************/ //null 和 " ...

  7. 【EF】EntityFramework DBFirst的使用

    一.前言        久闻EF大名,之前做C/S产品用的是Dapper对SqlLite进行ORM.然后接触公司授权系统后发现用的是EntityFramework对SQLSever进行ORM.授权系统 ...

  8. 代码收藏系列--javascript--日期函数

    /** * 获取当前时间的简短函数 * @returns {String} * @@example getTimeStamp() 结果是:2017-07-12 09:21:30 */ function ...

  9. 「CodePlus 2017 12 月赛」可做题2(矩阵快速幂+exgcd+二分)

    昨天这题死活调不出来结果是一个地方没取模,凉凉. 首先有个一眼就能看出来的规律... 斐波那契数列满足$a_1, a_2, a_1+a_2, a_1+2a_2, 2a_1+3a_2, 3a_1+5a_ ...

  10. bzoj4144【AMPPZ2014】Petrol

    题解:  首先注意到起点和终点都是加油站;          假设中途经过某个非加油站的点u,u连到v,离u最近的加油站是x,那么从u到x加油后回到u,再到v一定不比直接从u到v差:        因 ...