您的位置:首页 > 其它

bzoj 3306: 树

2017-10-12 21:16 190 查看

Description

给定一棵大小为 n 的有根点权树,支持以下操作:

换根

修改点权

查询子树最小值

Input

第一行两个整数 n,Q ,分别表示树的大小和操作数。

接下来 n 行,每行两个整数
17d57
f,v ,第 i+1 行的两个数表示点 i 的父亲和点 i 的权。保证 f<i。如果f=0,那么 i 为根。输入数据保证只有i=1时,f=0。

接下来 m 行,为以下格式中的一种:

Vxy 表示把点 x 的权改为 y

Ex 表示把有根树的根改为点 x

Qx 表示查询点 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≤105

solution

这道题先把整个树dfs一下,搞出dfs序来,那修改点权和查询最小值就是裸的线段树了

就是换根看上去有点难,来考虑一下根对查询操作的影响

假设我们要查的那个节点是x,根为 root

if(x=root) 显然这个时候就是查询整棵树的最小值

if(x≠root) ,这个时候又要分两种情况来考虑

如果我们把根换到不是 x 的子树的点,那么这个时候对 x 是没什么影响



如我我们把根从 root 换到 a ,并不会影响到 x 的子树,所以这个时候和平常一样query就好

如果我们把根换到属于 x 的子树的点

一开始如果树长这个样



我们把根换到属于 x 的子树的点 a ,那树就成了这个样子



对比一下上面那个图,我们发现换根之后要查询的范围就是不换根之前所有的店除了 a 和 a 的子树

把这个推广一下就可以了

code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

template<typename T>
void input(T &x) {
x=0; T a=1;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-') a=-1;
for(;c>='0'&&c<='9';c=getchar())
x=x*10+c-'0';
x*=a;
return;
}

#define MAXN 100010

struct Edge {
int u,v,next;
Edge(int u=0,int v=0,int next=0):
u(u),v(v),next(next) {}
};

Edge edge[MAXN];
int head[MAXN],cnt=0;

void addedge(int u,int v) {
edge[++cnt]=Edge(u,v,head[u]);
head[u]=cnt;
return;
}

int dfn[MAXN],last[MAXN],order[MAXN],timee;

int fa[MAXN][21],depth[MAXN];

void dfs(int u) {
order[++timee]=u;
dfn[u]=timee;
for(int i=head[u];i;i=edge[i].next)
if(edge[i].v!=fa[u][0]) {
depth[edge[i].v]=depth[u]+1;
dfs(edge[i].v);
}
last[u]=timee;
return;
}

int w[MAXN];

struct Segment_Tree {
int l,r,Min;
};

Segment_Tree t[MAXN<<2];

void updata(int now) {
t[now].Min=min(t[now<<1].Min,t[now<<1|1].Min);
return;
}

void build(int now,int l,int r) {
t[now].l=l,t[now].r=r;
if(l==r) {
t[now].Min=w[order[l]];
return;
}
int mid=l+r>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
updata(now);
return;
}

void Modify(int now,int pos,int x) {
int l=t[now].l,r=t[now].r;
if(l==r) {
t[now].Min=x;
return;
}
int mid=l+r>>1;
if(pos<=mid) Modify(now<<1,pos,x);
else Modify(now<<1|1,pos,x);
updata(now);
return;
}

#define inf 2147483647

int query(int now,int L,int R) {
if(L>R) return inf;
int l=t[now].l,r=t[now].r;
if(l==L&&R==r) return t[now].Min;
int mid=l+r>>1;
if(R<=mid) return query(now<<1,L,R);
else if(L>mid) return query(now<<1|1,L,R);
else {
int a=query(now<<1,L,mid),
b=query(now<<1|1,mid+1,R);
return min(a,b);
}
}

int up(int x,int depth) {
for(int i=19;i>=0;i--)
if(depth&(1<<i)) x=fa[x][i];
return x;
}

int main() {
int n,T,root=1;
input(n),input(T);
input(fa[1][0]),input(w[1]);
for(int i=2;i<=n;i++) {
input(fa[i][0]),input(w[i]);
addedge(fa[i][0],i);
}
dfs(1);
for(int j=1;j<=19;j++)
for(int i=1;i<=n;i++)
if(fa[i][j-1])
fa[i][j]=fa[fa[i][j-1]][j-1];
build(1,1,n);
char op[3];
int x,y;
while(T--) {
scanf("%s",op);
input(x);
if(op[0]=='V') {
input(y);
Modify(1,dfn[x],y);
} else if(op[0]=='E') root=x;
else if(root==x) printf("%d\n",query(1,1,n));
else if(dfn[x]<=dfn[root]&&last[root]<=last[x]) {
y=up(root,depth[root]-depth[x]-1);
printf("%d\n",min(query(1,1,dfn[y]-1),query(1,last[y]+1,n)));
} else printf("%d\n",query(1,dfn[x],last[x]));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: