gym102861E. Party Company

本文针对Codeforces平台上的特定竞赛题目进行了解析,提出了一种通过DFS序和差分数组解决子树问题的方法,并进一步优化至使用权值树状数组进行区间统计,实现了高效的查询更新操作。

https://codeforces.com/gym/102861/problem/E

听课也更不上,比赛过了一车人的题也不会,没了啊

这题很显然我们可以看出,由于最后一定是一个连通块属于同一个组,那么由组长o我们可以倍增到最上面的领导o1,使得最上面恰好逼近r

那么最显然的想法就是从这个根节点o1开始,他子树中所有>=l的都会+1,那么子树问题显然可以用dfs序来维护,按dfs序标号,然后分块对每块内部排序,然后左右边界的块暴力找,中间的块一定在子树中,就直接二分后用差分数组作区间加法

O(nsqrt(n)logn)快乐TLE

然后就要从另一个角度考虑统计答案了,我们把每一个小组信息挂在根节点o1上,dfs的时候就把从根节点到当前节点所有小组信息加载进权值树状数组里,然后看这些小组信息有多少是当前节点u满足的,就是这个点的答案

上面是分块代码,下面是有点卡常的代码。。。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int maxl=2e5+10;

int n,m,sz,ind,tot;
int val[maxl],aval[maxl],dfn[maxl],out[maxl],ans[maxl];
int bel[maxl],ll[maxl],rr[maxl];
LL b[maxl],c[maxl];
int f[21][maxl];
vector<int> e[maxl];
struct node
{
	int val,id,dy;
}a[maxl];

inline void dfs(int u,int fa)
{
	dfn[u]=++ind;
	a[ind].val=-val[u];a[ind].id=ind;a[ind].dy=u;
	for(int v:e[u])
		dfs(v,u);
	out[u]=ind;
}

inline bool cmp(const node &x,const node &y)
{
	return x.val<y.val;
}

inline void prework()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&val[i],&f[0][i]);
		if(i!=1)
			e[f[0][i]].push_back(i);
	}
	f[0][1]=0;
	for(int k=1;k<=20;k++)
		for(int i=1;i<=n;i++)
			f[k][i]=f[k-1][f[k-1][i]];
	dfs(1,0);
	sz=sqrt(n);
	for(int i=1;i<=n;i++)
	{
		bel[i]=(i-1)/sz+1;
		if(!ll[bel[i]])
			ll[bel[i]]=i;
		rr[bel[i]]=i;
	}
	for(int i=1;i<=bel[n];i++)
		sort(a+ll[i],a+rr[i]+1,cmp);
	for(int i=1;i<=n;i++)
		aval[i]=a[i].val;
}

inline void mainwork()
{
	for(int cas=1;cas<=m;cas++)
	{
		int o,l,r;
		scanf("%d%d%d",&o,&l,&r);
		for(int k=20;k>=0;k--)
		if(f[k][o]!=0 && val[f[k][o]]<=r)
			o=f[k][o];
		int lb=(dfn[o]-1)/sz+1,rb=(out[o]-1)/sz+1;
		for(int i=lb+1;i<=rb-1;i++)
		if(a[ll[i]].val<=-l)
		{
			int rd=upper_bound(aval+ll[i],aval+rr[i]+1,-l)-aval;
			c[ll[i]]++;c[rd]--;
		}
		for(int j=ll[lb];j<=rr[lb];j++)
		if(a[j].id>=dfn[o] && a[j].id<=out[o] && a[j].val<=-l)
			ans[a[j].dy]++;
		if(lb==rb)
			continue;
		for(int j=ll[rb];j<=rr[rb];j++)
		if(a[j].id>=dfn[o] && a[j].id<=out[o] && a[j].val<=-l)
			ans[a[j].dy]++;
	}
	for(int i=1;i<=n;i++)
		c[i]+=c[i-1],ans[a[i].dy]+=c[i];
}

inline void print()
{
	for(int i=1;i<=n;i++)
		printf("%d%c",ans[i]," \n"[i==n]);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int maxl=3e5+10;

int n,m,sz,ind,tot;
int val[maxl],ans[maxl];
int f[21][maxl];
int b[maxl],num[maxl];
vector<int> e[maxl],g[maxl];
struct que
{
	int o,l,r;
}q[maxl];

inline void prework()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&val[i],&f[0][i]);
		num[++tot]=val[i];
		if(i!=1)
			e[f[0][i]].push_back(i);
	}
	f[0][1]=0;
	for(int k=1;k<=20;k++)
		for(int i=1;i<=n;i++)
			f[k][i]=f[k-1][f[k-1][i]];
}

inline int id(int x)
{
	return lower_bound(num+1,num+1+tot,x)-num;
}

inline void add(int i,int x)
{
	while(i && i<=tot)
		b[i]+=x,i+=i&-i;
}

inline int sum(int i)
{
	int ret=0;
	while(i)
		ret+=b[i],i-=i&-i;
	return ret;
}

inline void dfs(int u,int fa)
{
	for(int l:g[u])
		add(l,1);
	ans[u]=sum(val[u]);
	for(int v:e[u])
		dfs(v,u);
	for(int l:g[u])
		add(l,-1);
}

inline void mainwork()
{
	for(int i=1;i<=m;i++)
	{
		int o,l,r;
		scanf("%d%d%d",&o,&l,&r);
		q[i]=que{o,l,r};
		num[++tot]=l;num[++tot]=r;
	}
	sort(num+1,num+1+tot);
	tot=unique(num+1,num+1+tot)-num-1;
	for(int i=1;i<=n;i++)
		val[i]=id(val[i]);
	for(int i=1;i<=m;i++)
	{
		q[i].l=id(q[i].l);
		q[i].r=id(q[i].r);
		int o=q[i].o,l=q[i].l,r=q[i].r;
		for(int k=20;k>=0;k--)
		if(f[k][o]!=0 && val[f[k][o]]<=r)
			o=f[k][o];
		g[o].push_back(l);
	}
	dfs(1,0);
}

inline void print()
{
	for(int i=1;i<=n;i++)
		printf("%d%c",ans[i]," \n"[i==n]);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

 

### 使用 `gym.spaces.Box` 定义动作空间 在OpenAI Gym环境中定义连续的动作空间通常会使用到 `gym.spaces.Box` 类。此类允许创建一个多维的盒子形状的空间,其边界由低限(low)和高限(high)参数指定[^1]。 对于给定的例子,在类 `ActionSpace` 中静态方法 `from_type` 返回了一个基于输入类型的行动空间实例: 当 `space_type` 是 `Continuous` 时,返回的是一个三维向量形式的动作空间对象,该对象表示三个维度上的取值范围分别为 `[0.0, 1.0]`, `[0.0, 1.0]`, 和 `[-1.0, 1.0]` 的实数集合,并且数据类型被设定为了 `np.float32`: ```python import numpy as np import gym class ActionSpace: @staticmethod def from_type(action_type: int): space_type = ActionSpaceType(action_type) if space_type == ActionSpaceType.Continuous: return gym.spaces.Box( low=np.array([0.0, 0.0, -1.0]), high=np.array([1.0, 1.0, 1.0]), dtype=np.float32, ) ``` 此段代码展示了如何通过传递最低限度(`low`)数组以及最高限度(`high`)数组来初始化一个新的Box实例,从而构建出一个具有特定界限的多维连续数值区间作为环境可能采取的一系列合法行为的选择集的一部分。 另外值得注意的是,每个环境都应当具备属性 `action_space` 和 `observation_space` ,这两个属性应该是继承自 `Space` 类的对象实例;Gymnasium库支持大多数用户可能会需要用到的不同种类的空间实现方式[^2]。 #### 创建并测试 Box 动作空间的一个简单例子 下面是一个简单的Python脚本片段用于展示怎样创建和验证一个基本的 `Box` 空间成员资格的方法: ```python def check_box_space(): box_space = gym.spaces.Box(low=-1.0, high=1.0, shape=(2,), dtype=np.float32) sample_action = box_space.sample() # 获取随机样本 is_valid = box_space.contains(sample_action) # 检查合法性 print(f"Sampled action {sample_action} within bounds? {'Yes' if is_valid else 'No'}") check_box_space() ``` 上述函数首先建立了一个二维的 `-1.0` 到 `1.0` 范围内的浮点型 `Box` 空间,接着从中抽取了一组随机样本来检验它确实位于所规定的范围内。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值