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

/**************************************************************
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. 找xpath好用的工具(比较少用,针对只能在IE上打开的网站)

    有一些网站只能在IE浏览器里打开,不像firefox那样有好多好用的插件来找元素的xpath,css path等. 当然现在IE也可以,F12出现像firebug那样的窗口,来查看元素. 这里呢在介绍 ...

  2. oracle impdp导入时 提示“ORA-39002: 操作无效 ORA-39070: 无法打开日志文件 ”

    第一步:首先使用DBA权限的用户创建directory,我使用system ,可以在服务器本地创建,也可以远程连接sqlplus进行创建,使用的将是服务器上面的路径.要确保创建directory时,操 ...

  3. php 多维数组排序

    PHP中array_multisort可以用来一次对多个数组进行排序,或者根据某一维或多维对多维数组进行排序. 关联(string)键名保持不变,但数字键名会被重新索引. 输入数组被当成一个表的列并以 ...

  4. 转---秒杀多线程第十二篇 多线程同步内功心法——PV操作上 (续)

    PV操作的核心就是 PV操作可以同时起到同步与互斥的作用. 1.同步就是通过P操作获取信号量,V操作释放信号量来进行. 2.互斥其实就是,同时操作P操作,结束后进行V操作即可做到. Java上实现PV ...

  5. Luogu4897 【模板】最小割树

    没事干写一发模板. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib& ...

  6. 【转】.gitignore失效的解决办法

    转自:http://foreverdo.diandian.com/post/2012-09-20/40038034798 How to make .gitignore works? Just got ...

  7. 【刷题】洛谷 P4716 【模板】最小树形图

    题目背景 这是一道模板题. 题目描述 给定包含 \(n\) 个结点, \(m\) 条有向边的一个图.试求一棵以结点 \(r\) 为根的最小树形图,并输出最小树形图每条边的权值之和,如果没有以 \(r\ ...

  8. 【转】大数据分析(Big Data OLAP)引擎Dremel, Tenzing 以及Impala

    引自:http://blog.csdn.net/xhanfriend/article/details/8434896 对于数据分析师来说,SQL是主要的语言. Hive为Hadoop提供了支持SQL运 ...

  9. 《剑指offer》— JavaScript(4)重建二叉树

    重建二叉树 题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序 ...

  10. 《剑指offer》— JavaScript(2)替换空格

    替换空格 题目描述 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 实现 ...