没怎么做过主席树的题,感觉思路好难想。。。
假设[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;
}