zoukankan      html  css  js  c++  java
  • CF703D Mishka and Interesting sum

    CF703D Mishka and Interesting sum

    洛谷传送门

    • 给定nn 个数的序列 aa。mm 次操作。操作有一种:
      1. l r:求 a_lsim a_ra**la**r 中,出现偶数次的数的异或和。
    • 1le n,mle 10^61≤n,m≤106,1le a_ile 10^91≤a**i≤109。

    题解:

    解决本题的关键是牢记异或的一个性质:异或一个数两次相当于异或了个寂寞。

    那么我们只需要想办法把一个区间出现奇数次的东西全搞没就好。就利用这个性质。

    我们先尝试着把整个区间的数都异或上去。发现,偶数次的数已经都异或成寂寞了,而奇数次的数各自保留了一个作为异或和的贡献。

    芜湖?那我们再把偶数次的数变成奇数次,奇数次的数还是奇数次,再异或上去,不就把奇数次的数都异或成寂寞,把偶数次的数都留下了一个么?

    思路豁然开朗:答案就是区间异或和异或上区间所含有的数(每个数只异或一次)的异或和

    区间异或和可以用异或的可差分性,用异或前缀和先处理好。

    那么区间所含有的数,每个数只异或一次,该怎么处理呢?

    用树状数组维护。还是抓住”异或一个数两次相当于异或了个寂寞“这个性质。只需要把这个数之前重复出现的数再异或一次,就相当于只保留了一个。但是这样的修改是有后效性的,也就是说,如果我们先处理后面的询问区间,就会提前把前面的区间修改掉,导致之后处理前面的区间时出错。于是我们把所有询问离线处理。维护pre数组表示这个数前面第一个和这个数一样的数的位置,就可以完成这一任务了。

    代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=1e6+6;
    int n,m;
    int a[maxn],b[maxn],sum[maxn];
    int head[maxn],pre[maxn];
    int ans[maxn];
    int tree[maxn];
    struct node
    {
    	int l,r,id;
    }q[maxn];
    bool cmp(node a,node b)
    {
    	if(a.r==b.r)
    		return a.l<b.l;
    	return a.r<b.r;
    }
    void update(int x,int k)
    {
    	for(int i=x;i<=n;i+=i&-i)
    		tree[i]^=k;
    }
    int query(int x)
    {
    	int ret=0;
    	for(int i=x;i;i-=i&-i)
    		ret^=tree[i];
    	return ret;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		b[i]=a[i];
    	}
    	sort(b+1,b+n+1);
    	int size=unique(b+1,b+n+1)-(b+1);
    	for(int i=1;i<=n;i++)
    		a[i]=lower_bound(b+1,b+size+1,a[i])-b;
    	for(int i=1;i<=n;i++)
    	{
    		pre[i]=head[a[i]];
    		head[a[i]]=i;
    		sum[i]=sum[i-1]^b[a[i]];
    	}
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&q[i].l,&q[i].r);
    		q[i].id=i;
    	}
    	sort(q+1,q+m+1,cmp);
    	int pos=1;
    	for(int i=1;i<=m;i++)
    	{
    		int l=q[i].l,r=q[i].r;
    		while(pos<=r)
    		{
    			if(pre[pos])
    				update(pre[pos],b[a[pos]]);
    			update(pos,b[a[pos]]);
    			pos++;
    		}
    		ans[q[i].id]=query(q[i].r)^query(q[i].l-1)^sum[r]^sum[l-1];
    	}
    	for(int i=1;i<=m;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    03server
    Storm介绍(一)
    storm总结
    Spring源码分析(七)扩展接口BeanPostProcessors源码分析
    技术大牛养成指南
    02装配bean
    02Activity
    maven构建项目
    IDEA使用
    从GIt上导出Maven项目
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14032527.html
Copyright © 2011-2022 走看看