1. 程式人生 > >Codeforces617E【莫隊演算法+字首異或】

Codeforces617E【莫隊演算法+字首異或】

題意:
給出一系列數,對每個查詢區間,計算有多少個子區間異或為k。
思路:
可以先預處理異或字首,一個區間[L,R]的異或值=sum[R]^sum[L-1];
如果當前區間是[a,b],加一個右端點b+1,那麼這個b+1的貢獻就是[a,b]區間內有多少個sum[x]=sum[b+1]^k
那麼我們可以每次記錄num[sum[x]]即num[sum[b+1]^k],並記錄num[sum[b+1]]++,同理左區間。

那麼我們就可以使用莫隊演算法。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=2e6+10;
int sum[N],pos[100010];
LL num[N];
int n,m,k,x;
struct asd{
    int left,right,id;
    LL res;
}e[100010];
bool cmp(asd x,asd y)
{
    if(pos[x.left]==pos[y.left]) return x.right<y.right;
    return pos[x.left]<pos[y.left];
}
LL ans; //答案遵守ans先加,再變;先變,ans再減;
void solve()
{
    sort(e,e+m,cmp);
    ans=0;
    memset(num,0,sizeof(num));
    int L=0,R=0;
    for(int i=0;i<m;i++)
    {
        while(L<e[i].left-1)                         //當他在區間左邊,他要減去他產生右端
        {
            num[sum[L]]--;                            //先變
            ans-=num[sum[L]^k];               //答案再減
            L++;
        }
        while(L>=e[i].left)                      //當他在區間右邊,他要加上他右端
        {
            L--;
            ans+=num[sum[L]^k];          //先加答案
            num[sum[L]]++;                      //再變
        }
        while(R<=e[i].right)                //小於,要加左邊
        {
            ans+=num[sum[R]^k];        //先加答案
            num[sum[R]]++;                   //再變
            R++;
        }
        while(R>e[i].right+1)               //大,要減左
        {
            R--;
            num[sum[R]]--;                      //先變
            ans-=num[sum[R]^k];         //再減答案
        }
        e[e[i].id].res=ans;
    }
    for(int i=0;i<m;i++)
        printf("%lld\n",e[i].res);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    sum[0]=0;
    int block=(int)sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        sum[i]=sum[i-1]^x;
        pos[i]=(i-1)/block+1;
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&e[i].left,&e[i].right);
        e[i].id=i;
    }
    solve();
    return 0;
}
/*
6 2 3
1 2 1 1 0 3
1 6
3 5
5 3 1
1 1 1 1 1
1 5
2 4
1 3
*/