码迷,mamicode.com
首页 > 编程语言 > 详细

Codeforces Round #365 (Div. 2) D - Mishka and Interesting sum(离线树状数组)

时间:2017-05-17 18:21:59      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:style   前缀   ret   依次   name   print   区间   ems   ring   

http://codeforces.com/contest/703/problem/D

题意:

给出一行数,有m次查询,每次查询输出区间内出现次数为偶数次的数字的异或和。

 

思路:

这儿利用一下异或和的性质,在一个区间中,我们如果把所有数字都异或的话,可以发现最后偶数次的数字异或后都变成了0,只剩下了奇数次的数字异或。

举个例子,{1,2,3,2,3,5}

异或和是1^2^3^2^3^5=1^5

因为最后要计算偶数次数字的异或和,那么最后我们只需要再异或上该区间内所有不同数字即可。

那么我们可以先计算出前缀异或和,之后就只要求区间上的不同数字的异或和即可。

离线树状数组和在线树状数组的不同点是前者是先把所有询问存储下来,排序后再处理。

拿这道题目来说,我们将询问按照右端点从小到大排序,然后依次计算询问,如果当前数字在之前已经出现过,那么就先删去它,然后再插入该数字,这样就保证了这个区间内不同的数字只出现一次,具体可见代码。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<string>
 6 #include<vector>
 7 #include<queue>
 8 #include<cmath>
 9 #include<map>
10 using namespace std;
11 typedef long long LL;
12 
13 const int maxn=1e6+5;
14 
15 struct node
16 {
17     int l,r;
18     int id;
19 }q[maxn];
20 
21 map<int,int> pos;
22 
23 int n,m;
24 int a[maxn];
25 int c[maxn];
26 int sum[maxn];
27 int pre[maxn];
28 LL ans[maxn];
29 
30 bool cmp(node a,node b)
31 {
32     return a.r<b.r||(a.r==b.r && a.l<b.l);
33 }
34 
35 int lowbit(int x)
36 {
37     return x&-x;
38 }
39 
40 int XOR_sum(int x)
41 {
42     int ret=0;
43     while(x>0)
44     {
45         ret^=c[x];
46         x-=lowbit(x);
47     }
48     return ret;
49 }
50 
51 void add(int x,int d)
52 {
53     while(x<=maxn)
54     {
55         c[x]^=d;
56         x+=lowbit(x);
57     }
58 }
59 
60 int main()
61 {
62     //freopen("D:\\input.txt","r",stdin);
63     while(~scanf("%d",&n))
64     {
65         pos.clear();
66         sum[0]=0;
67         for(int i=1;i<=n;i++)
68         {
69             scanf("%d",&a[i]);
70             sum[i]=sum[i-1]^a[i];
71             pre[i]=pos[a[i]];   //记录a[i]这个数前面出现的位置
72             pos[a[i]]=i;   //更新a[i]最晚的出现位置
73         }
74         scanf("%d",&m);
75         for(int i=0;i<m;i++)
76         {
77             scanf("%d%d",&q[i].l,&q[i].r);
78             q[i].id=i;
79         }
80         sort(q,q+m,cmp);
81         memset(c,0,sizeof(c));
82         for(int i=0,r=1;i<m;i++)
83         {
84             while(r<=q[i].r)
85             {
86                 if(pre[r])    //如果第r个位置的数之前已经出现过,就删去这个数
87                     add(pre[r],a[r]);
88                 add(r,a[r]);   //添加第r个数
89                 r++;
90             }
91             ans[q[i].id]=XOR_sum(q[i].r)^XOR_sum(q[i].l-1)^sum[q[i].r]^sum[q[i].l-1];
92         }
93         for(int i=0;i<m;i++)
94             printf("%I64d\n",ans[i]);
95     }
96     return 0;
97 }

 

Codeforces Round #365 (Div. 2) D - Mishka and Interesting sum(离线树状数组)

标签:style   前缀   ret   依次   name   print   区间   ems   ring   

原文地址:http://www.cnblogs.com/zyb993963526/p/6868659.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!