Codeforces 703D
题目链接:http://acm.hust.edu.cn/vjudge/problem/450060
题目大意: 给出一个长度为n的序列a (a<=10^9),询问m次,每次询问区间[l,r]之内出现偶数个数的数的异或和。
分析:
我们先利用异或前缀和,这样问题转化为在区间[l,r]中出现过的数异或和。
对于这样一个问题,我们不妨先看另外一个问题:动态查询区间[l,r]内不同的数的个数。
我们先离线处理,将询问按右端点排序,设Last[val]为val在当前序列中最后一次出现的位置,cnt[i]=1 当且经当last[a[i]]=i,则答案即为[l,r]的cnt和。
当右端点移动时,用Fenwick Tree更新a[i]的值更新last和cnt,将之前的last值与cnt更新,在O(nlogn)的时间内求出答案。
再回到原问题,我们只需将求和改为异或和,将cnt[i]=1改为cnt[i]=a[i],离散化就解决了。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())
using namespace std;
typedef long long LL;
const int maxn=1000000+27;
struct node{
int l,r,num,ans;
} q[maxn];
int T[maxn],last[maxn],a[maxn],s[maxn],u[maxn],size,n,m,k,last_r,prex[maxn],cnt[maxn];
bool cmp(node a,node b) {return a.r<b.r;}
bool cmp2(node a,node b) {return a.num<b.num;}
bool ucmp(int a,int b) {return s[a]<s[b];}
void init() //离散化
{
rep(i,1,n) u[i]=i;
sort(u+1,u+n+1,ucmp);
k=0,size=0;
while (k<n)
{
k++,size++;
while (k<=n)
{
a[u[k]]=size;
if (s[u[k+1]]!=s[u[k]]) break;
k++;
}
}
}
void set(int x,int val) //修改cnt值
{
int k=x;
while (x<=n) T[x]=(T[x]^cnt[k])^val,x+=(x&(-x));
}
int sum(int x) //求异或和
{
int s=0;
while (x>0) s^=T[x],x-=(x&(-x));
return s;
}
int main()
{
scanf("%d",&n);
rep(i,1,n) scanf("%d",&s[i]);
init();
scanf("%d",&m);
rep(i,1,m)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].num=i;
}
sort(q+1,q+m+1,cmp); //对询问排序
k=0,last_r=0;
while (k<m)
{
k++;
rep(i,last_r+1,q[k].r) //对相同右端点集中更新
{
if (last[a[i]]) set(last[a[i]],0),cnt[last[a[i]]]=0;
last[a[i]]=i,set(i,s[i]),cnt[i]=s[i];
}
last_r=q[k].r;
while (k<=m)
{
q[k]. ans=sum(q[k].r)^sum(q[k].l-1);
if (q[k+1].r!=q[k].r) break;
k++;
}
}
sort(q+1,q+m+1,cmp2);
rep(i,1,n) prex[i]=prex[i-1]^s[i]; //前缀和
rep(i,1,m) printf("%d\n",(q[i].ans)^(prex[q[i].r]^prex[q[i].l-1]));
return 0;
}

浙公网安备 33010602011771号