3306: 树
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 715 Solved: 235
[ Submit][ Status][ Discuss]
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。
Source
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 1E5 + 10;
const int INF = ~0U>>1;
int n,m,clo,root,in[maxn],out[maxn],c[maxn*20],fa[maxn][20],w[maxn],L[maxn];
vector<int> v[maxn];
void Modify(int o,int l,int r,int pos,int modi)
{
if (l == r) {c[o] = modi; return;}
int mid = (l+r) >> 1;
if (pos <= mid) Modify(2*o,l,mid,pos,modi);
else Modify(2*o+1,mid+1,r,pos,modi);
c[o] = min(c[2*o],c[2*o+1]);
}
void dfs(int k)
{
in[k] = ++clo;
for (int i = 1; i < 20; i++) fa[k][i] = fa[fa[k][i-1]][i-1];
for (int i = 0; i < v[k].size(); i++) {
int to = v[k][i];
L[to] = L[k] + 1; dfs(to);
}
Modify(1,1,n,in[k],w[k]);
out[k] = clo;
}
int query(int o,int l,int r,int ql,int qr)
{
if (l > r) return INF;
if (ql <= l && r <= qr) return c[o];
int mid = (l+r) >> 1,ret = INF;
if (ql <= mid) ret = min(ret,query(2*o,l,mid,ql,qr));
if (qr > mid) ret = min(ret,query(2*o+1,mid+1,r,ql,qr));
return ret;
}
int LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
int Log; for (Log = 0; L[p] - (1<<Log) >= 1; Log++); --Log;
for (int j = Log; j >= 0; j--)
if (L[p] - (1<<j) >= L[q])
p = fa[p][j];
if (p == q) return p;
for (int j = Log; j >= 0; j--)
if (fa[p][j] != fa[q][j])
p = fa[p][j],q = fa[q][j];
return fa[p][0];
}
int find(int x,int y)
{
for (int j = 19; j >= 0; j--)
if (y - (1 << j) >= 0)
x = fa[x][j],y -= (1<<j);
return x;
}
int getcom()
{
char ch = getchar();
while (ch != 'V' && ch != 'E' && ch != 'Q')
ch = getchar();
if (ch == 'V') return 1;
if (ch == 'E') return 2;
return 3;
}
int main()
{
#ifdef YZY
freopen("yzy.txt","r",stdin);
#endif
cin >> n >> m;
for (int i = 1; i <= n; i++) {
int x; scanf("%d%d",&x,&w[i]);
if (!x) root = i; else v[x].push_back(i),fa[i][0] = x;
}
L[root] = 1; dfs(root);
while (m--) {
int typ = getcom();
if (typ == 1) {
int x,y; scanf("%d%d",&x,&y);
Modify(1,1,n,in[x],y);
}
else if (typ == 3) {
int x; scanf("%d",&x);
int lca = LCA(root,x);
if (x == root) printf("%d\n",query(1,1,n,1,n));
else if (lca == root || (lca != x && lca != root))
printf("%d\n",query(1,1,n,in[x],out[x]));
else {
int k;
if (L[root] - L[x] == 1) k = root;
else k = find(root,L[root] - L[x] - 1);
printf("%d\n",min(query(1,1,n,1,in[k]-1),query(1,1,n,out[k]+1,n)));
}
}
else scanf("%d",&root);
}
return 0;
}