您的位置:首页 > 其它

BZOJ 3306|树|树链剖分

2016-02-14 18:46 363 查看
和bzoj 3083比就是弱化版了。

样例都有点像?

http://blog.csdn.net/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
, sz
, son
, top
, c
, f
, fa
, dep
, pos
, cnt = 0;
int end
, 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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: