1. 程式人生 > >Loj 2534 異或序列

Loj 2534 異或序列

struct dig 移動 space ans 直接 esp class inline

Loj 2534 異或序列

  • 考慮莫隊離線處理.每加一個數,直接詢問 \(a[x]\oplus k\) 的前/後綴數目即可,減同理.
  • 利用異或的優秀性質,可以維護異或前綴和,容易做到每次 \(O(1)\) 移動區間端點.

很久沒寫莫隊了.有一個小細節開始寫錯了:如果 \(a.belong\) 是根據 \(a.l\) 算出的,排序時的第二關鍵字就選取 \(a.r\) ,否則會被卡到 \(O(n^2)\) .

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
    int x=0;
    bool pos=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            pos=0;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
const int MAXN=1e5+10,N=2e5;
struct query{
    int l,r,bel;
    int ans,id;
}q[MAXN];
bool cmp1(query a,query b)
{
    if(a.bel!=b.bel)
        return a.bel<b.bel;
    if(a.r!=b.r)
        return a.r<b.r;
    return a.l<b.l; 
}
bool cmp2(query a,query b)
{
    return a.id<b.id;
}
int n,m,k;
int ans=0;
int a[MAXN],pre[MAXN],cnt[MAXN<<1];
void Add(int x)
{
    ans+=cnt[k^pre[x]]; 
    ++cnt[pre[x]];
}
void Remove(int x)
{
    --cnt[pre[x]];
    ans-=cnt[k^pre[x]];
}
int main()
{
    n=read(),m=read(),k=read();
    int bsiz=sqrt(n);
    for(int i=1;i<=n;++i)
        a[i]=read(),pre[i]=pre[i-1]^a[i];
    for(int i=1;i<=m;++i)
        {
            q[i].l=read(),q[i].r=read();
            q[i].bel=(q[i].l-1)/bsiz;
            q[i].id=i;
        }
    sort(q+1,q+1+m,cmp1);
    int L=1,R=0;
    for(int i=1;i<=m;++i)
        {
            int l=q[i].l,r=q[i].r;
            while(L<l-1)
                Remove(L++);
            while(L>l-1)
                Add(--L);
            while(R<r)
                Add(++R);
            while(R>r)
                Remove(R--);
            q[i].ans=ans;
        }
    sort(q+1,q+1+m,cmp2);
    for(int i=1;i<=m;++i)
        printf("%d\n",q[i].ans);
    return 0;
}

Loj 2534 異或序列