BZOJ 3083 遥远的国度 树链剖分

13 篇文章 0 订阅

奇怪了以前见过这题的。。
题意:换根+子树查+链改。
树链剖分裸题。
换根讨论情况。
怎么样就只能第二页了。。
markdown的代码插入语言不能写c++得写cpp?

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100005, M = N * 3, inf = 0x7fffffff;
int read() {
    int s = 0, f = 1; char ch = getchar();
    for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
    for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
    return s * f;
}

int next[M], to[M], head[N], sz[N], son[N], top[N], c[N], f[N], fa[N], dep[N], pos[N], cnt = 0;
int end[N], num[M], lazy[M], rt, n, tot = 0;

void add(int u, int v) {
    next[++cnt] = head[u]; head[u] = cnt; to[cnt] = v;
    next[++cnt] = head[v]; head[v] = cnt; to[cnt] = u;
}

void dfs1(int x) {  
    sz[x] = 1; son[x] = 0;  
    for (int i = head[x]; i; i = next[i])  
        if (to[i] != fa[x]) {  
            fa[to[i]] = x; dep[to[i]] = dep[x] + 1;  
            dfs1(to[i]);  
            if (sz[to[i]] > sz[son[x]]) son[x] = to[i];  
            sz[x] += sz[to[i]];  
        }  
}  

void dfs2(int x, int t) {  
    pos[x] = ++tot; top[x] = t;  
    if (son[x] != 0) dfs2(son[x], t);  
    for (int i = head[x]; i; i = next[i])  
        if (to[i] != son[x] && to[i] != fa[x])  
            dfs2(to[i], to[i]); 
    end[x] = tot;
}

void pushdown(int t) {
    if (lazy[t]) {
        num[t * 2 + 1] = lazy[t * 2 + 1] = num[t * 2] = lazy[t * 2] = lazy[t];
        lazy[t] = 0;
    }
}

void modify(int t, int l, int r, int ql, int qr, int z) {
    int mid = l + r >> 1;
    if (l == ql && r == qr) { num[t] = lazy[t] = z; return; }
    pushdown(t);
    if (qr <= mid) modify(t * 2, l, mid, ql, qr, z);
    else if (mid < ql) modify(t * 2 + 1, mid + 1, r, ql, qr, z);
    else modify(t * 2, l, mid, ql, mid, z), modify(t * 2 + 1, mid + 1, r, mid + 1, qr, z);
    num[t] = min(num[t * 2], num[t * 2 + 1]);
}

void modify(int x, int y, int z) {
    int fx = top[x], fy = top[y];
    while (fx != fy) {
        if (dep[fx] < dep[fy]) swap(fx, fy), swap(x, y);
        modify(1, 1, n, pos[fx], pos[x], z);
        x = fa[x], fx = top[x];
    }
    if (dep[x] > dep[y]) swap(x, y);
    modify(1, 1, n, pos[x], pos[y], z);
}

int query(int t, int l, int r, int ql, int qr) {
    int mid = l + r >> 1;
    if (l == ql && r == qr) return num[t];
    pushdown(t);
    if (qr <= mid) return query(t * 2, l, mid, ql, qr);
    else if (mid < ql) return query(t * 2 + 1, mid + 1, r, ql, qr);
    else return min(query(t * 2, l, mid, ql, mid), query(t * 2 + 1, mid + 1, r, mid + 1, qr));
}

int query(int x) {
    if (x == rt) return query(1, 1, n, 1, n);
    if (pos[rt] < pos[x] || pos[rt] > end[x]) return query(1, 1, n, pos[x], end[x]);
    int i, ans = inf;
    for (i = head[x]; i; i = next[i])
        if (pos[rt] >= pos[to[i]] && pos[rt] <= end[to[i]] && to[i] != fa[x]) {
            if (pos[to[i]] > 1)
                ans = min(ans, query(1, 1, n, 1, pos[to[i]] - 1));
            if (end[to[i]] < n)
                ans = min(ans, query(1, 1, n, end[to[i]] + 1, n));
            break;
        }
    return ans;
}

void build(int t, int l, int r) {
    int mid = l + r >> 1;
    if (l == r) { num[t] = c[l]; return; }
    build(t * 2, l, mid); build(t * 2 + 1, mid + 1, r);
    num[t] = min(num[t * 2], num[t * 2 + 1]);
}

int main() {
    int i, j, m;
    n = read(); m = read();
    for (i = 1; i < n; i++) add(read(), read());
    for (i = 1; i <= n; i++) f[i] = read();
    rt = read();
    dfs1(rt); dfs2(rt, rt);
    for (i = 1; i <= n; i++) c[pos[i]] = f[i];
    build(1, 1, n);
    while (m--) 
        switch(read()) {
        case 1: rt = read(); break;
        case 2: i = read(); j = read(); modify(i, j, read()); break;
        case 3: printf("%d\n", query(read())); break;
        }
    return 0;
}

3083: 遥远的国度

Time Limit: 10 Sec Memory Limit: 1280 MB
Submit: 1974 Solved: 489

描述

zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

Input

第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

Output

对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

Sample Input

3 7

1 2

1 3

1 2 3

1

3 1

2 1 1 6

3 1

2 2 2 5

3 1

2 3 3 4

3 1

Sample Output

1

2

3

4

提示

对于20%的数据,n<=1000 m<=1000。

对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。

对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。

对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。

对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值