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

/**************************************************************
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. libcurl底层调用逻辑

    libcurl就不多介绍了,一个支持HTTP,FTP,SMTP等协议的网络库 只涉及multi部分,easy部分就不提了. 两个线程,一个负责添加HTTP请求,另一个轮询,负责处理每一个请求 Thre ...

  2. laraven安装记录

    版本4.2.11 下载地址:https://codeload.github.com/laravel/laravel/zip/v4.2.11 步骤: 1.解压到目录 2.下载composer,并放到/u ...

  3. POSt 提交参数 实体 和字符串

    //1.后台接受是 字符串形式 [HttpPost] public int SendTaxiAudioByWX(string userid, string suid, string indexno, ...

  4. windows远程连接设置

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

  5. PHP对象的遍历

    对象的遍历 对象的遍历,跟数组的遍历,一样! 其实,只能遍历出对象的“实例属性数据” foreach( $对象名  as   $key => $value){ //这里就可以处理$key和$va ...

  6. PHP中is_null()方法

    is_null — 检测变量是否为 NULL bool is_null ( mixed $var ) 如果 var 是 null 则返回 TRUE,否则返回 FALSE.  举例: $x=" ...

  7. bzoj3961[WF2011]Chips Challenge

    题意 给出一个n*n的网格,有些格子必须染成黑色,有些格子必须染成白色,其他格子可以染成黑色或者白色.要求最后第i行的黑格子数目等于第i列的黑格子数目,且某一行/列的格子数目不能超过格子总数的A/B. ...

  8. Android四大组件之Activity & Fragement(续)

    1.Activity和Fragment的异同. Activity是UI界面交互的主体,而fragment是这个主体上的元素. 一个activity可以包含0到n个fragment. fragment可 ...

  9. 【开发工具IDE】Eclipse相关配置

    1. 修改workspace编码为UTF-8 1.1. 修改jsp编码为UTF-8 2. 修改字体 3. 添加系统中的JDK 4. 导入formatter模板 5. 修改maven配置文件 打开文件: ...

  10. P4005 小 Y 和地铁

    题目描述 小 Y 是一个爱好旅行的 OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的一条曲线,不同线路的交点处一定会设有 换乘站 . ...