\(1, 2\)操作没什么好说的

对于\(3\)操作,分三种情况讨论下

\(id = rt\)的情况下,查整棵树的最小值即可

如果\(rt\)在\(1\)号点为根的情况下不在\(id\)的子树中,那么查\(1\)号点为根的情况下\(id\)的子树即可

否则,找到\(rt\)到\(id\)链中\(id\)的儿子,整棵树去掉这个子树就是\(id\)新的子树


然而我太懒了,不想打倍增

于是我们考虑用树剖来解决这个问题

分两种情况

如果最后\(id\)和\(id\)的儿子处于一条重链,那么返回\(son[id]\)

否则,返回最后访问的轻链顶


复杂度\(O(n \log^2 n)\)


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; #define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --) #define gc getchar
inline int read() {
int p = 0, w = 1; char c = gc();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = gc(); }
while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
return p * w;
} const int sid = 4e5 + 5; int n, m, rt, id, cnp;
int cap[sid], nxt[sid], node[sid];
int anc[sid], val[sid], grd[sid], ind[sid], dfn[sid];
int sz[sid], dep[sid], cov[sid], fa[sid], son[sid]; inline void addedge(int u, int v) {
nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v;
} #define cur node[i]
inline void dfs(int o) {
sz[o] = 1;
for(int i = cap[o]; i; i = nxt[i])
if(cur != fa[o]) {
fa[cur] = o;
dep[cur] = dep[o] + 1;
dfs(cur);
sz[o] += sz[cur];
if(sz[cur] > sz[son[o]]) son[o] = cur;
}
} inline void dfs(int o, int ac) {
anc[o] = ac; dfn[o] = ++ id; ind[id] = o;
if(!son[o]) return;
dfs(son[o], ac);
for(int i = cap[o]; i; i = nxt[i])
if(cur != fa[o] && cur != son[o])
dfs(cur, cur);
} #define ls (o << 1)
#define rs (o << 1 | 1) inline void build(int o, int l, int r) {
if(l == r) { val[o] = grd[ind[l]]; return; }
int mid = (l + r) >> 1;
build(ls, l, mid); build(rs, mid + 1, r);
val[o] = min(val[ls], val[rs]);
} inline void pcov(int o, int v) {
val[o] = cov[o] = v;
} inline void pushcov(int o) {
if(!cov[o]) return;
pcov(ls, cov[o]); pcov(rs, cov[o]);
cov[o] = 0;
} inline void mdf(int o, int l, int r, int ml, int mr, int v) {
if(ml > r || mr < l) return;
if(ml <= l && mr >= r) { pcov(o, v); return; }
pushcov(o);
int mid = (l + r) >> 1;
mdf(ls, l, mid, ml, mr, v);
mdf(rs, mid + 1, r, ml, mr, v);
val[o] = min(val[ls], val[rs]);
} const int inf = 2147483647;
inline int qry(int o, int l, int r, int ml, int mr) {
if(ml > r || mr < l || ml > mr) return inf;
if(ml <= l && mr >= r) return val[o];
pushcov(o);
int mid = (l + r) >> 1;
return min(qry(ls, l, mid, ml, mr), qry(rs, mid + 1, r, ml, mr));
} inline void mdf(int u, int v, int w) {
int pu = anc[u], pv = anc[v];
while(pu != pv) {
if(dep[pu] < dep[pv]) swap(u, v), swap(pu, pv);
mdf(1, 1, n, dfn[pu], dfn[u], w);
u = fa[pu]; pu = anc[u];
}
if(dep[u] > dep[v]) swap(u, v);
mdf(1, 1, n, dfn[u], dfn[v], w);
} inline int up(int o, int top) {
int po = anc[o], pv = anc[top];
while(po != pv) {
if(fa[po] == top) return po;
o = fa[po]; po = anc[o];
}
return son[top];
} int main() {
n = read(); m = read();
rep(i, 2, n) {
int u = read(), v = read();
addedge(u, v); addedge(v, u);
}
rep(i, 1, n) grd[i] = read();
dfs(1); dfs(1, 1); build(1, 1, n);
rt = read();
rep(i, 1, m) {
int opt = read();
if(opt == 1) rt = read();
else if(opt == 2) {
int u = read(), v = read(), w = read();
mdf(u, v, w);
}
else {
int ip = read();
if(ip == rt) printf("%d\n", val[1]);
else {
if(dfn[ip] <= dfn[rt] && dfn[rt] <= dfn[ip] + sz[ip] - 1) {
int t = up(rt, ip);
printf("%d\n", min(qry(1, 1, n, 1, dfn[t] - 1), qry(1, 1, n, dfn[t] + sz[t], n)));
}
else printf("%d\n", qry(1, 1, n, dfn[ip], dfn[ip] + sz[ip] - 1));
}
}
}
return 0;
}

luoguP3979 遥远的国度 树链剖分的更多相关文章

  1. BZOJ 3083 遥远的国度 树链剖分

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 797  Solved: 181[Submit][Status] Descrip ...

  2. BZOJ 3083 遥远的国度(树链剖分+LCA)

    Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...

  3. 【bzoj3083】遥远的国度 树链剖分+线段树

    题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...

  4. BZOJ 3083: 遥远的国度(树链剖分+DFS序)

    可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...

  5. BZOJ 3083 遥远的国度 树链剖分+线段树

    有换根的树链剖分的裸题. 在换根的时候注意讨论. 注意数据范围要开unsigned int或longlong #include<iostream> #include<cstdio&g ...

  6. 洛谷P3979 遥远的国度 树链剖分+分类讨论

    题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...

  7. BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 1280 MBSubmit: 3127  Solved: 795[Submit][Status][Discu ...

  8. [日常摸鱼]bzoj3083遥远的国度-树链剖分

    一无聊就找树剖写 题意:一颗带点权的树,三种操作:1.换根 2.链赋值 3.查询子树最小值 如果没有换根的话直接就是裸的树剖了,对于换根的操作我们可以分类讨论. 1.如果查询的$x$就是根,那答案就是 ...

  9. BZOJ 3083 遥远的国度 树链剖分+脑子

    唉..又调了半天QWQ..为何读入挂了.....莫非读入是反着的????据ywy学长所言如是...OvO震惊 这啥骚题啊...还要换根...不过清明讲过...(然鹅我现在才做... 先随便选个点(比如 ...

随机推荐

  1. 8、String练习题

    String练习   1.字符串反转,例如将"abc"变成"cba" 2.统计一个字符串里面另一个字符串出现的次数,例如统计"monkey" ...

  2. 多校 HDU 6397 Character Encoding (容斥)

    题意:在0~n-1个数里选m个数和为k,数字可以重复选: 如果是在m个xi>0的情况下就相当于是将k个球分割成m块,那么很明显就是隔板法插空,不能为0的条件限制下一共k-1个位置可以选择插入隔板 ...

  3. Treats for the Cows 区间DP POJ 3186

    题目来源:http://poj.org/problem?id=3186 (http://www.fjutacm.com/Problem.jsp?pid=1389) /** 题目意思: 约翰经常给产奶量 ...

  4. MeasureSpec介绍及使用详解

    一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求.一个MeasureSpec有大小和模式组成.他有三种模式: UNSPECIFIED ...

  5. Redis—数据结构之sds

    Redis是一个Key Value数据库.Redis有5种数据类型:字符串.列表.哈希.集合.有序集合.而字符串的底层实现方法之一就是使用sds.以下描述中请读者注意区分sds是指简单动态字符串这一数 ...

  6. Docker技术这些应用场景【转】

    场景一:节省项目环境部署时间 1.单项目打包 每次部署项目到测试.生产等环境,都要部署一大堆依赖的软件.工具,而且部署期间出现问题几率很大,不经意就花费了很长时间. Docker主要理念就是环境打包部 ...

  7. php CI框架

    CodeIgniter 是一个小巧但功能强大的 PHP 框架,作为一个简单而“优雅”的工具包,它可以为 PHP 程序员建立功能完善的 Web 应用程序.如果你是一个使用共享主机,并且为客户所要求的期限 ...

  8. html-表格和列表

    一:表格标签 表格 描述 <table> 定义表格 <caption> 定义表格标题. <th> 定义表格的表头. <tr> 定义表格的行. <t ...

  9. Merkle tree在区块链中的应用

    上篇博文我们转载了一篇<Merkle Tree(默克尔树)算法解析>,那么大家是不是会有疑问,学习这个算法之后,我们改怎么去应用,区块链中又是如何应用的?今天这篇博客就以Merkle tr ...

  10. INSTEAD OF与AFTER触发器

    INSTEAD OF 触发器 AFTER 触发器(也叫“FOR”触发器)会在触发 insert.update 或是delect 动作之后执行.例如,一个 Employees 表上的 AFTER 触发器 ...