2018牛客多校第五场 F take[树状数组]

发布时间 2023-08-09 17:31:25作者: qbning

理解题目画了一个二叉树,然后思维定势让我想构建一个有n层的二叉树,然后统计叶子节点。。有点恐怖。

但是正解是考虑每一个箱子对答案的贡献。

图片来自take_baymax520的博客

对于每个箱子,它要发生交换也就是为答案贡献的条件是它当前宝石大小小于它的大小。对于比它小的宝石之前取(pi)或不取(1-pi)都是无所谓的。

而之前比它大的宝石只有不取(1-pi)时,当前宝石才能对答案产生贡献。那么每个宝石的贡献就如上图了。

然后是用的树状数组维护的前缀积。

树状数组应该有两种思路,一种是按照下标排序,另一种是离散化按照大小排序。

如果要按照下标排序的话,我们需要保证比它小的数不能先出现。此时保证查询它的前缀和的时候,比它小的的位置上是1而不是(1-pi)。所以我们建树操作的时候按照宝石大小从大到小排序即可

按照下标排序的树状数组
#include<iostream>
#include<algorithm>
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
const ll mod=998244353;
pair<ll,ll> exgcd(ll a)
{
    ll b=mod;
	pair<ll,ll>x,y;
	x=make_pair(1,0);
	y=make_pair(0,1);
	while(b)
	{
		ll q=a/b;
		x=make_pair(x.first-y.first*q,x.second-y.second*q);
		a%=b;
		swap(a,b);
		swap(x,y);
	}
	return x;
}
ll _inv(int x)
{
	return (exgcd(x).first+mod)%mod;
}
int n;
struct node
{
	ll d,p,num;
}a[100005];
ll tree[100005],__;
void add(int num,ll p)
{
	while(num<=n)
	{
		tree[num]=(tree[num]*p)%mod;
		num+=lowbit(num);
	}
}
ll ask(int num)
{
	ll ans=1;
	while(num)
	{
		ans=(ans*tree[num])%mod;
		num-=lowbit(num);
	}
	return ans;
}
signed main()
{
	__=_inv(100);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		tree[i]=1;
		cin>>a[i].p>>a[i].d;
		a[i].num=i;
		a[i].p=(a[i].p*__)%mod;
	}
    //按照大小排序
	sort(a+1,a+1+n,[](node x,node y)->bool{return x.d>y.d;});
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		ans=(ans+(a[i].p*ask(a[i].num)%mod))%mod;
		add(a[i].num,1-a[i].p+mod);
	}
	cout<<ans;
	return 0;
}

如果按照大小排序的话,我们需要保证坐标比它大的不能提前出现,那么按照坐标排序即可。

代码根据上面的改一改就是,所以推荐上面那个

按照大小排序的树状数组
 #include<iostream>
#include<algorithm>
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
const ll mod=998244353;
pair<ll,ll> exgcd(ll a)
{
    ll b=mod;
	pair<ll,ll>x,y;
	x=make_pair(1,0);
	y=make_pair(0,1);
	while(b)
	{
		ll q=a/b;
		x=make_pair(x.first-y.first*q,x.second-y.second*q);
		a%=b;
		swap(a,b);
		swap(x,y);
	}
	return x;
}
ll _inv(int x)
{
	return (exgcd(x).first+mod)%mod;
}
int n;
struct node
{
	ll d,p,num;
}a[100005];
ll tree[100005],__;
void add(int num,ll p)
{
	while(num<=n)
	{
		tree[num]=(tree[num]*p)%mod;
		num+=lowbit(num);
	}
}
ll ask(int num)
{
	ll ans=1;
	while(num)
	{
		ans=(ans*tree[num])%mod;
		num-=lowbit(num);
	}
	return ans;
}
signed main()
{
	__=_inv(100);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		tree[i]=1;
		cin>>a[i].p>>a[i].d;
		a[i].num=i;
		a[i].p=(a[i].p*__)%mod;
	}
	//离散化
	sort(a+1,a+1+n,[](node x,node y)->bool{return x.d>y.d;});
	for(int i=1;i<=n;i++)
		a[i].d=i;
	//按照坐标排序
	sort(a+1,a+1+n,[](node x,node y)->bool{return x.num<y.num;});
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		ans=(ans+(a[i].p*ask(a[i].d)%mod))%mod;
		add(a[i].d,1-a[i].p+mod);
	}
	cout<<ans;
	return 0;
}