CF703D Mishka and Interesting sum

题意

给定序列a,给定 m 个询问\(l,r\),要求每个询问回答\([l,r]\)内出现次数为偶数的数的异或和

题解

发现直接前缀和异或,得到的是出现次数为奇数的数的异或和

于是问题转化成了求出区间内出现过的数的异或和

将询问离线按右端点排序,线段树做扫描线

具体来说就是记一个 last 数组,\(last_i\) 表示i 这个数上一次出现的位置

每次右端点移动,\([last_i+1,i]\)区间内\(a_i\)第一次出现,区间修改,单点查询

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+11;
struct qry_{
	int l;
	int num;
};
struct tree{
	int l,r;
	int sum;
	int lazy;
}tre[4*N];
int n,m;
int a[N],lsh[N];
int ans[N];
int last[N];
int qzh[N];
vector<qry_> vct[N];
inline int read()
{
	int s=0;
	char ch=getchar();
	while(ch>'9'||ch<'0') ch=getchar();
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s;
}
void lsh_()
{
	sort(lsh+1,lsh+n+1);
	int x=unique(lsh+1,lsh+n+1)-lsh;
	for(int i=1;i<=n;++i) a[i]=lower_bound(lsh+1,lsh+x,a[i])-lsh;
	return;
}
void pushdown(int i)
{
	if(tre[i].l==tre[i].r)return;
	tre[i<<1].lazy^=tre[i].lazy;
	tre[i<<1|1].lazy^=tre[i].lazy;
	tre[i<<1].sum^=tre[i].lazy;
	tre[i<<1|1].sum^=tre[i].lazy;
	tre[i].lazy=0;
	return;
}
void build(int i,int l,int r)
{
	tre[i]=(tree){l,r,0};
	if(l==r) return;
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	return;
}
int query(int i,int x)
{
	if(tre[i].lazy)pushdown(i);
	if(tre[i].l==tre[i].r) return tre[i].sum;
	int mid=(tre[i].l+tre[i].r)>>1;
	if(x<=mid) return query(i<<1,x);
	else return query(i<<1|1,x);
}
void insert(int i,int l,int r,int val)
{
	if(tre[i].lazy)pushdown(i);
	if(tre[i].l>=l&&tre[i].r<=r){tre[i].lazy^=val;tre[i].sum^=val;return;}
	int mid=(tre[i].l+tre[i].r)>>1;
	if(l<=mid) insert(i<<1,l,r,val);
	if(r>mid) insert(i<<1|1,l,r,val);
	tre[i].sum=tre[i<<1].sum^tre[i<<1|1].sum;
	return;
}
int main()
{
	n=read();
	for(int i=1;i<=n;++i) a[i]=lsh[i]=read(),qzh[i]=qzh[i-1]^a[i];
	lsh_();
	m=read();
	for(int l,r,i=1;i<=m;++i)
	{
		l=read(),r=read();
		vct[r].push_back({l,i});
	}
	build(1,1,n);
	for(int i=1;i<=n;++i)
	{
		if(last[a[i]]) insert(1,1,last[a[i]],lsh[a[i]]);
		insert(1,1,i,lsh[a[i]]);
		last[a[i]]=i;
		for(int j=0;j<vct[i].size();++j) ans[vct[i][j].num]=query(1,vct[i][j].l)^qzh[i]^qzh[vct[i][j].l-1];
	}
	for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
	return 0;
}
上一篇:单向链表和双向链表的添加操作


下一篇:防御sql注入之参数化查询