Stone Games(icpc昆明,主席树)

传送门

没怎么做过主席树的题,感觉思路好难想。。。

假设[1,x]中每个数都可以被表示出来,如果现在加个y,y属于[1, x],那么[1, x+y]这段区间也可以被表示出来,如果[1 ,x+y]这段区间又有新的数,那么这段区间又会增加。
所以我们s从0开始,每次查询[1,s+1]这段区间的和,如果不变说明答案就是s+1,否则就继续找。
为什么是到s+1呢,因为你1到s都可以表示出来,那么如果有值为s+1,那么s+1就可以表示出来,否则就不能,也就找到答案了。

我们用主席树维护第i棵树在[x,y]这个值域的和。
然后,,就很模板了。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#define LL long long
using namespace std;
const int maxn=1e6+10;
const LL inf=1e9+10;

LL a[maxn];
struct node
{
	int L,r;
	LL sum;
}hjt[maxn*40];
int root[maxn*40],cnt;
void ins(LL L,LL r,int pre,int &now,LL p)
{
	hjt[++cnt]=hjt[pre];
	now=cnt;
	hjt[now].sum+=p;
	if(L==r)return ;
	LL mid=(L+r)>>1;
	if(p<=mid) ins(L,mid,hjt[pre].L,hjt[now].L,p);
	else ins(mid+1,r,hjt[pre].r,hjt[now].r,p);
}

LL query(LL st,LL ed,LL L,LL r,int x,int y)
{
	if(st<=L&&r<=ed)
	{
		return hjt[y].sum-hjt[x].sum;
	}
	LL mid=(L+r)>>1,ans=0;
	if(st<=mid)ans+=query(st,ed,L,mid,hjt[x].L,hjt[y].L);
	if(ed>mid)ans+=query(st,ed,mid+1,r,hjt[x].r,hjt[y].r);
	return ans;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=n;i++)
	{
		ins(1,inf,root[i-1],root[i],a[i]);
	}
	LL L,r,tmp,res,ans=0;
	while(m--)
	{
		scanf("%lld%lld",&L,&r);
		L=(L+ans)%n+1,r=(r+ans)%n+1;
		if(L>r)swap(L,r);
		res=0;
		while(1)
		{
			tmp=query(1,min(inf,res+1),1,inf,root[L-1],root[r]);
			if(tmp==res)break;
			res=tmp;
		}
		ans=res+1;
		printf("%lld\n",ans);
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值