SnackDown 2017 Online Elimination Round #Prefix Xor -- 主席树

来源:互联网 发布:mac如何双开战网 编辑:程序博客网 时间:2024/06/05 12:53

传送门

题目大意:

给你 n 个数,每个数的值是 ai ,定义数对 (i,j) 是上升的当且仅当

aiai xor ai+1ai xor ai+1 xor ai+2ai xor ai+1 xor ai+2xor aj

Q 个询问,每个询问给出两个整数 li,ri,求liijri的上升数对(i,j)的个数。

题解:

fi表示最大的 j ,满足 (i,j) 为上升数对。
考虑第 k 个数,假设 xak 二进制最大非 0 位。
那么只有当 ai xor ai+1akx 位为 1 时满足ai xor ai+1ak<ai xor ai+1ak1
枚举二进制每一位,更新 fi。由于要强制在线,用主席树维护 fi

代码:

这里写代码片#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define N 400010#define ll long long#define M 31char ss[30];int Len;inline void Print(ll x){    if(!x){        putchar(48);puts("");        return;    }    for(Len=0;x;x/=10)ss[++Len]=x%10;    while(Len)putchar(ss[Len--]+48);puts("");}struct Node{    ll w,t;    int s,l,r;}c[N*80];ll s2,s3,Ans;int i,j,k,n,m,p,a[N],f[N],Q,Mi[2],b[N],Rt[N],Num,s1,x,y;bool z;inline int Min(int x,int y){    return x<y?x:y;}inline int Get(int x){    for(int i=M-1;i>=0;i--)    if(x&(1<<i))return i;    return -1;}inline void Insert(int& x,int y,int l,int r,int z,int p,int q){    x=++Num;    c[x]=c[y];    c[x].s++;c[x].w+=q;c[x].t+=p;    if(l==r)return;    int Mid=l+r>>1;    if(z<=Mid)Insert(c[x].l,c[y].l,l,Mid,z,p,q);else Insert(c[x].r,c[y].r,Mid+1,r,z,p,q);}inline void Query1(int x,int y,int l,int r,int L,int R){    if(!y||l>R||r<L)return;    if(l>=L&&r<=R){        s2+=c[y].w-c[x].w;        return;    }    int Mid=l+r>>1;    Query1(c[x].l,c[y].l,l,Mid,L,R);    Query1(c[x].r,c[y].r,Mid+1,r,L,R);}inline void Query2(int x,int y,int l,int r,int L,int R){    if(!y||l>R||r<L)return;    if(l>=L&&r<=R){        s1+=c[y].s-c[x].s;s3+=c[y].t-c[x].t;        return;    }    int Mid=l+r>>1;    Query2(c[x].l,c[y].l,l,Mid,L,R);    Query2(c[x].r,c[y].r,Mid+1,r,L,R);}int main(){    scanf("%d",&n);    for(i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=Get(a[i]),f[i]=n;    for(i=0;i<M;i++){        Mi[0]=Mi[1]=n+1;z=0;        for(j=n;j;j--){            f[j]=Min(f[j],Mi[z^(a[j]&(1<<i)?1:0)]-1);            if(b[j]==i)Mi[z]=j;z^=a[j]&(1<<i)?1:0;        }    }    for(i=1;i<=n;i++)Insert(Rt[i],Rt[i-1],1,n,f[i],i,f[i]-i+1);    scanf("%d",&Q);    while(Q--){        scanf("%d%d",&x,&y);        x=(Ans%n+x)%n+1;y=(Ans%n+y)%n+1;        if(x>y)swap(x,y);        s1=s2=s3=0;        Query1(Rt[x-1],Rt[y],1,n,x,y);        if(y<n)Query2(Rt[x-1],Rt[y],1,n,y+1,n);        Ans=s2-s3+1ll*(y+1)*s1;        Print(Ans);    }    return 0;}