奇怪了以前见过这题的。。
题意:换根+子树查+链改。
树链剖分裸题。
换根讨论情况。
怎么样就只能第二页了。。
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。