comet OJ #8 D 菜菜种菜

传送门:https://cometoj.com/contest/58/problem/D

其实是个水题,不过我当场没有想起来先求一个总的,再用另一个树状数组维护另一个,减去多余的这种套路

我们预处理对于每一个点 a[i].id  ,他在 [ a[i].ll , a[i].rr ]区间之内不会有可以直接到的点,那么我们按照a[i].ll排序

再对所有的询问的区间按照左端点排序。

对于每一个询问que[i], 他的答案其实是所有满足  que[i].l<=a[i].id<=que[i].r  ,  a[i].l<=que[i].l, a[i].r >= que[i].r的这些菜地的a[i].w之和

维护两个树状数组,b1表示a[i].r为下标的a[i].w的前缀和,b2表示a[i].id为下标的a[i].r的前缀和

那么我们从左到右枚举询问,再设个a数组的,如果a[idx+1].l<=que[i].l 就加入,并更新b1,b2,记录一个decpos[i],表示a[i].id=i的有哪些下标,那么如果a[i].id<que[i].l,是不满足条件的,需要减去。

那么首先用b1算出那些 a[i].id>=que[i].l (前提已经保证),且a[i].rr>=que[i].r的 a[i].w之和,但是由于a[i].id需要<= que[i].r ,且哪些a[i].id>que[i].r 的,a[i].r>que[i].r,所以用b2算出a[i].id>que[i].r的多余的a[i].w和,从之前的总和中减去就是答案。

#include<bits/stdc++.h>
#define maxl 1000010
using namespace std;

int n,m,q;
long long b1[maxl],b2[maxl],ans[maxl];
struct node
{
	int ll,rr;
	int w,id;
	bool operator < (const node &b)const
	{
		return id<b.id;
	}
	bool operator == (const node &b)const
	{
		return id==b.id;
	}
}a[maxl];
vector <int> decpos[maxl];
struct qu
{
	int l,r,id;
}que[maxl];

inline bool nodecmp(const node &x,const node &y)
{
	if(x.ll==y.ll)
		return x.id<y.id;
	return x.ll<y.ll;
}
inline bool quecmp(const qu &x,const qu &y)
{
	if(x.l==y.l)
		return x.r<y.r;
	return x.l<y.l;	
}

inline void prework()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)
	{
		a[i].id=i,a[i].ll=1;a[i].rr=n;
		scanf("%d",&a[i].w);
	}
	int u,v;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		if(v>u)
			a[u].rr=min(a[u].rr,v-1);
		if(v<u)
			a[u].ll=max(a[u].ll,v+1);
	}
	sort(a+1,a+1+n,nodecmp);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&que[i].l,&que[i].r);
		que[i].id=i;
	}
	sort(que+1,que+1+q,quecmp);
}

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

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

inline void mainwork()
{
	int idx=0,l,x;
	for(int i=1;i<=q;i++)
	{
		while(a[idx+1].ll<=que[i].l && idx<n)
		{
			++idx;
			add(b1,a[idx].rr,a[idx].w);
			add(b2,a[idx].id,a[idx].w);
			decpos[a[idx].id].push_back(idx);
		}
		for(int j=que[i-1].l;j<=que[i].l-1;j++)
		{
			l=decpos[j].size();
			for(int k=0;k<l;k++)
			{
				x=decpos[j][k];
				add(b1,a[x].rr,-a[x].w);
				add(b2,a[x].id,-a[x].w);
			}
		}
		ans[que[i].id]=sum(b1,n)-sum(b1,que[i].r-1);
		ans[que[i].id]-=sum(b2,n)-sum(b2,que[i].r);
	}
}

inline void print()
{
	long long x=0;
	for(int i=1;i<=q;i++)
		x^=i*ans[i];
	printf("%lld\n",x);
}

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值