HDU 3333 | Codeforces 703D 树状数组、离散化

HDU 3333:http://acm.hdu.edu.cn/showproblem.php?pid=3333

这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序。这里我们需要离散化处理一下,标记一下前面是否出现过这个值,然后不断更新last数组(该数组保存的是每个数最后一次出现的位置)。最后用树状数组维护。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 33333;
 5 const int maxq = 111111;
 6 struct node{
 7     int l,r,index;
 8 };
 9 node query[maxq];
10 ll sum[maxn],ans[maxq];
11 ll a[maxn],b[maxn],last[maxn];
12 int n;
13 bool cmp(node a,node b){
14     return a.r < b.r;
15 }
16 ll getsum(int i){
17     ll s = 0;
18     while(i > 0){
19         s += sum[i];
20         i -= i&(-i);
21     }
22     return s;
23 }
24 void add(int i,ll x){
25     while(i <= n){
26         sum[i] += x;
27         i += i&(-i);
28     }
29 }
30 int main(){
31     int t;
32     scanf("%d",&t);
33     while(t--){
34         scanf("%d",&n);
35         for(int i = 1;i<=n;i++){
36             scanf("%I64d",&a[i]);
37             b[i] = a[i];//离散化用 
38         }
39         sort(b+1,b+1+n);//排序,以每个数的下标标记 
40         int q;
41         scanf("%d",&q);
42         for(int i = 1;i<=q;i++){
43             scanf("%d%d",&query[i].l,&query[i].r);
44             query[i].index = i;
45         }
46         sort(query+1,query+1+q,cmp);
47         memset(sum,0,sizeof(sum));
48         memset(last,0,sizeof(last));
49         int cnt = 1;//每个查询的下标 
50         for(int i = 1;i<=n;i++){
51             int index = lower_bound(b+1,b+1+n,a[i])-b-1;//找到该数对应的下标 
52             if(last[index])//判断该数是否出现过,有的话减去 
53                 add(last[index],-a[i]);
54             add(i,a[i]);
55             last[index] = i;
56             while(query[cnt].r==i && cnt<=q){
57                 ans[query[cnt].index] = getsum(query[cnt].r)-getsum(query[cnt].l-1);
58                 cnt++;
59             }
60         }
61         for(int i = 1;i<=q;i++)
62             printf("%I64d\n",ans[i]);
63     }    
64     return 0;
65 } 
View Code

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

这道题需要多思考的一步是,要求的区间内出现偶数次的数的异或和,等于这个区间内所有数字的异或和异或这个区间内不同数字的异或和,以1、2、1、3、3、2、3举例,结果就是(1^2^1^3^3^2^3)^(1^2^3),原理就是出现偶数次的数异或它自己等于它本身,出现奇数次的数异或它自己为0。对于区间的异或和,我们可以用数组很方便的求出,不同数字的异或和,只需要对上题进行一下改造就好了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 const int maxn = 1111111;
 6 struct node{
 7     int l,r,index;
 8 };
 9 node query[maxn];
10 ll sum[maxn],a[maxn],b[maxn],c[maxn],last[maxn],ans[maxn];
11 int n;
12 bool cmp(node a,node b){
13     return a.r < b.r;
14 }
15 ll getsum(int i){
16     ll s = 0;
17     while(i > 0){
18         s ^= sum[i];//注意 
19         i -= i&(-i);
20     }
21     return s;
22 }
23 void add(int i,ll x){
24     while(i <= n){
25         sum[i] ^= x;//注意 
26         i += i&(-i);
27     }
28 }
29 int main(){
30     scanf("%d",&n);
31     for(int i = 1;i<=n;i++){
32         scanf("%I64d",&a[i]);
33         c[i] = a[i]^c[i-1];//求前缀异或和 
34         b[i] = a[i];
35     }
36     sort(b+1,b+1+n);
37     int q;
38     scanf("%d",&q);
39     for(int i = 1;i<=q;i++){
40         scanf("%d%d",&query[i].l,&query[i].r);
41         query[i].index = i;
42     }
43     sort(query+1,query+1+q,cmp);
44     int cnt = 1;
45     for(int i = 1;i<=n;i++){
46         int index = lower_bound(b+1,b+1+n,a[i])-b-1;
47         if(last[index])
48             add(last[index],a[i]);
49         last[index] = i;
50         add(i,a[i]);
51         while(query[cnt].r==i && cnt<=q){
52             ans[query[cnt].index] = (c[query[cnt].r]^c[query[cnt].l-1])^(getsum(query[cnt].r)^getsum(query[cnt].l-1));//注意 
53             cnt++;
54         }
55     }
56     for(int i = 1;i<=q;i++)
57         printf("%I64d\n",ans[i]);
58     return 0;
59 }
View Code

 

posted @ 2016-08-07 16:26  张秦遥  阅读(364)  评论(0编辑  收藏  举报