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

/**************************************************************
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. 设计模式PHP篇(三)————装饰器模式

    简单的用php实现了装饰器模式: <?php /** *简单的装饰器模式 */ class PrintText { protected $decorators = []; public func ...

  2. el表达式作用域查找顺序 注意:当属性名字相同时候 先找到是小的作用域 因为是从小到大开始找的

  3. (三)MySQL学习笔记

    [Leecode]175. 组合两个表 解答:由于是组合两个表的信息,很容易想到连接查询,这里使用左连接 select p.Firstname,p.Lastname,q.City,q.State fr ...

  4. mysql安装使用详细教程

    1.数据库存储数据的方式与Excel类似. 一.数据库介绍 1.什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库, 每个数据库都有一个或多个不同的API用于创建,访 ...

  5. jQuery多重事件绑定

    1. <a> a标签默认绑定了一个onclick事件,当自己再写一个onclick事件的时候,默认自己写的那个优先执行. 如下程序,先执行(123),然后再发生跳转. <!DOCTY ...

  6. 【刷题】洛谷 P3806【模板】点分治1

    题目背景 感谢hzwer的点分治互测. 题目描述 给定一棵有n个点的树 询问树上距离为k的点对是否存在. 输入输出格式 输入格式: n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径 接 ...

  7. javascript中的位运算,

    罗浮宫群里又有讨论位运算符号|了,做过一段时间php,数据库保存布尔值数据经常用到,比如100110 就表明了六个属性的是与否,极大减少了数据量..] ECMAScript 中位运算跟其他语言一样的. ...

  8. Xml中SelectSingleNode方法,xpath查找某节点用法

    Xml中SelectSingleNode方法,xpath查找某节点用法 最常见的XML数据类型有:Element, Attribute,Comment, Text. Element, 指形如<N ...

  9. Codeforces Round #301 (Div. 2)A B C D 水 模拟 bfs 概率dp

    A. Combination Lock time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  10. STL源码分析-hashtable

    http://note.youdao.com/noteshare?id=5c8d2b09c0f72af9a12b0ed2023a338d