BZOJ 3306|树|树链剖分

和bzoj 3083比就是弱化版了。
样例都有点像?
http://blog.youkuaiyun.com/huanghongxun/article/details/50663457

#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 = 1, 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[fx], 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() {
    char op[2];
    int i, j, m;
    n = read(); m = read();
    for (i = 1; i <= n; i++) add(i, read()), f[i] = read();
    dfs1(rt); dfs2(rt, rt);
    for (i = 1; i <= n; i++) c[pos[i]] = f[i];
    build(1, 1, n);
    while (m--) { 
        scanf("%s", op);
        switch(op[0]) {
        case 'E': rt = read(); break;
        case 'V': i = read(); j = read(); modify(i, i, j); break;
        case 'Q': printf("%d\n", query(read())); break;
        }
    }
    return 0;
}

3306: 树

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 608 Solved: 192

Description

给定一棵大小为 n 的有根点权树,支持以下操作:
* 换根
* 修改点权
* 查询子树最小值

Input

  第一行两个整数 n, Q ,分别表示树的大小和操作数。
  接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权。保证f < i。如 果f = 0,那么i为根。输入数据保证只有i = 1时,f = 0。
  接下来 m 行,为以下格式中的一种:
  • V x y表示把点x的权改为y
  • E x 表示把有根树的根改为点 x
  • Q x 表示查询点 x 的子树最小值

Output

对于每个 Q ,输出子树最小值。

Sample Input

3 7
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1

Sample Output

1
2
3
4

HINT

对于 100% 的数据:n, Q ≤ 10^5。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值