题目概述
有一个序列
{an}
,
(i,j)
是上升的需要满足:
令
Sk=ai xor ai+1⋯ xor ak(i≤k≤j)
,则
Si≤Si+1⋯≤Sj
。
对于一组
l,r
,求满足
l≤i≤j≤r
的上升
(i,j)
的数量,强制在线。
解题报告
为每一个点
i
记录
暂时先不管累计的效率,如果没有好的方法求出
MAX[i]
,肯定是会超时的。
令
Sumk=a1 xor a2⋯xor ak
,考虑一个不满足的情况:
Sumr xor Sumi−1>Sumr+1 xor Sumi−1
,这意味着
MAX[i]≤r
,即
MAX[i]=min{r|Sumr xor Sumi−1>Sumr+1 xor Sumi−1}
。
由于是位运算,考虑二进制:
Sumr xor Sumi−1>Sumr+1 xor Sumi−1
当且仅当
Sumr
和
Sumr+1
二进制中至少存在一位不相同,假设不相同的最高位是第
k
位,那么
1.
2.
Sumr
的第
k
位是
那么倒着枚举
i
,记录
然后我们来看累计,如果 [l,r] 不存在 MAX[i]>r ,那么答案显然就是 ∑ri=l{MAX[i]−i+1|MAX[i]≤r} ,但如果存在 MAX[i]>r ,由于不能越界,该部分的答案应该就是 ∑ri=l{r−i+1|MAX[i]>r} ,我们需要求出这种情况的个数。由于强制在线,用主席树就可以解决了。
示例程序
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=400000,Log=30;
int n,te,sum[maxn+5],lst[Log+5][2],MAX[maxn+5];
LL ans;
struct node
{
node *son[2];int num;LL sum;
node(int a,LL b,node *l=0,node *r=0) {son[0]=l;son[1]=r;num=a;sum=b;}
void Pushup() {num=son[0]->num+son[1]->num;sum=son[0]->sum+son[1]->sum;}
};
typedef node* P_node;
P_node ro[maxn+5];
inline bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
inline char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
inline int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9'<ch||ch<'0') {if (ch==EOF) return ch;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
return x=tot*f,Eoln(ch);
}
P_node Build(int L,int R)
{
P_node p=new node(0,0);int mid=L+(R-L>>1);
if (L==R) return p;
p->son[0]=Build(L,mid);p->son[1]=Build(mid+1,R);
p->Pushup();return p;
}
P_node Insert(P_node p,int pos,int l=1,int r=n)
{
P_node now=new node(p->num+1,p->sum+pos,p->son[0],p->son[1]);
if (l==r) return now;int mid=l+(r-l>>1);
if (pos<=mid) now->son[0]=Insert(p->son[0],pos,l,mid); else
now->son[1]=Insert(p->son[1],pos,mid+1,r);
now->Pushup();return now;
}
int Num(P_node A,P_node B,int L,int R,int l=1,int r=n)
{
if (R<l||r<L) return 0;if (L<=l&&r<=R) return B->num-A->num;
int mid=l+(r-l>>1);
return Num(A->son[0],B->son[0],L,R,l,mid)+Num(A->son[1],B->son[1],L,R,mid+1,r);
}
LL Sum(P_node A,P_node B,int L,int R,int l=1,int r=n)
{
if (R<l||r<L) return 0;if (L<=l&&r<=R) return B->sum-A->sum;
int mid=l+(r-l>>1);
return Sum(A->son[0],B->son[0],L,R,l,mid)+Sum(A->son[1],B->son[1],L,R,mid+1,r);
}
LL SumL(int L,int R) {return (LL)(L+R)*(R-L+1)/2-(R-L+1);}
#define Pos(x,len) (((x)>>(len))&1)
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);for (int i=1,x;i<=n;i++) readi(x),sum[i]=sum[i-1]^x;
for (int i=0;i<=Log;i++) lst[i][0]=lst[i][1]=n;
for (int i=n;i>=1;i--)
{
int MIN=n;for (int j=0;j<=Log;j++) MIN=min(MIN,lst[j][Pos(sum[i-1],j)]);
MAX[i]=MIN;
for (int j=Log;j>=0;j--) if (Pos(sum[i-1],j)^Pos(sum[i],j))
{lst[j][Pos(sum[i],j)]=i-1;break;}
}
ro[0]=Build(1,n);for (int i=1;i<=n;i++) ro[i]=Insert(ro[i-1],MAX[i]);
for (readi(te);te;te--)
{
int L,R;readi(L);readi(R);
L=(L+ans)%n+1;R=(R+ans)%n+1;
if (L>R) swap(L,R);
printf("%lld\n",ans=Sum(ro[L-1],ro[R],L,R)+(LL)Num(ro[L-1],ro[R],R+1,n)*R-SumL(L,R));
}
return 0;
}