【线段树】2022年10月20日A组 歪脖子树

题目描述

在这里插入图片描述

输入

在这里插入图片描述

数据规模

在这里插入图片描述

思路

在这里插入图片描述

代码

#include<iostream>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define lc(k) k<<1
#define rc(k) k<<1|1
using namespace std;
const int N=2e6+2,inf=1e9;
struct node
{
	int l,r,mid;
	int val;
}tree[N];
char op;
int n,q,rt=1,tot;
int a[N],l[N],r[N],st[N][21],dep[N];
int he[N],ne[N],to[N],cnt;
void add(int u,int v)
{
	cnt++;
	ne[cnt]=he[u];
	he[u]=cnt;
	to[cnt]=v;
}
void build(int k,int l,int r)
{
	tree[k].l=l,tree[k].r=r;
	tree[k].val=inf;
	if(l==r) return;
	tree[k].mid=(l+r)>>1;
	build(lc(k),l,tree[k].mid);
	build(rc(k),tree[k].mid+1,r);
}
void pushup(int k){tree[k].val=min(tree[lc(k)].val,tree[rc(k)].val);}
void update(int k,int l,int r,int val)
{
	if(tree[k].l==l&&tree[k].r==r)
	{
		tree[k].val=val;
		return;
	}
	if(r<=tree[k].mid) update(lc(k),l,r,val);
	if(tree[k].mid+1<=l) update(rc(k),l,r,val);
	pushup(k);
}
int query(int k,int l,int r)
{
	if(l>r) return inf;
	if(tree[k].l==l&&tree[k].r==r) 
	return tree[k].val;
	if(r<=tree[k].mid) return query(lc(k),l,r);
	else if(tree[k].mid+1<=l) return query(rc(k),l,r);
	else return min(query(lc(k),l,tree[k].mid),query(rc(k),tree[k].mid+1,r));
}
void dfs(int u)
{
	l[u]=++tot;
	dep[u]=dep[st[u][0]]+1;
	update(1,l[u],l[u],a[u]);
	for(int i=he[u];i;i=ne[i])
	dfs(to[i]);
	r[u]=++tot;
}
int main()
{
	scanf("%d%d",&n,&q);
	build(1,1,2*n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&st[i][0],&a[i]);
		if(st[i][0]) add(st[i][0],i);
	}
	dfs(1);
	//求dfs序,建出dfs序区间上的线段树 
	for(int j=1;j<=20;j++)
	for(int i=1;i<=n;i++)
	st[i][j]=st[st[i][j-1]][j-1];
	//倍增跳祖先 
	for(int i=1,x,y;i<=q;i++)
	{
		cin>>op;
		if(op=='V')
		{
			scanf("%d%d",&x,&y);
			update(1,l[x],l[x],y);//单点修改 
		}
		if(op=='E')
		scanf("%d",&rt);
		if(op=='Q')
		{
			scanf("%d",&x);
			if(l[x]<l[rt]&&r[rt]<r[x])//rt在x的子树内 (不含x)
			{
				y=rt;
				for(int step=20;step>=0;step--)
				if(dep[st[y][step]]>dep[x]) y=st[y][step];
				//将rt跳到x在以1为根情况下的亲儿子 
				printf("%d\n",min(query(1,1,l[y]-1),query(1,r[y]+1,2*n)));
				//查询dfs序区间上的一个前缀和后缀并(整棵树(以1为根)去掉y的子树)
			}
			else if(x==rt) printf("%d\n",query(1,1,2*n));
			//rt为x,查询整棵树 
			else printf("%d\n",query(1,l[x],r[x]));
			//rt在x的子树外,查询dfs序区间上的一个区间((以1为根)x的子树) 
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值