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

HDU 3333:http://blog.csdn.net/julyana_lin/article/details/7877164

这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序。这里我们需要离散化处理一下,标记一下前面是否出现过这个值,然后不断更新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 } 

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 }

时间: 2024-10-13 15:38:09

HDU 3333 | Codeforces 703D 树状数组、离散化的相关文章

HDU 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include

hdu 3333 Turing Tree (树状数组+离线处理+离散化)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3981    Accepted Submission(s): 1349 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems a

HDU 3333 Turing Tree (树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3333 题意就是询问区间不同数字的和. 比较经典的树状数组应用. 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstrin

hdu 3333 Turing Tree(树状数组离线操作)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3904    Accepted Submission(s): 1325 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems

hdu 5372 Segment Game(树状数组+离散化)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5372 题意:有两种操作,输入a b,①a==0,插入第i条线段[b,b+i],输出[b,b+i]内有多少条完全包含于[b,b+i]的线段②a==1,删除插入的第b条线段. 分析:由于插入的线段长度是递增的,那么就不存在包含[b,b+i]的线段.那么完全包含于[b,b+i]的线段的数目=右端点小于等于b+i的线段的数目-左端点小于b的线段的数目.由于输入的数比较大,离散化一下就行了. 代码: #inclu

HDU 2227 Find the nondecreasing subsequences (DP+树状数组+离散化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2227 Find the nondecreasing subsequences                                  Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                             

hdu4325 树状数组+离散化

http://acm.hdu.edu.cn/showproblem.php?pid=4325 Problem Description As is known to all, the blooming time and duration varies between different kinds of flowers. Now there is a garden planted full of flowers. The gardener wants to know how many flower

HDU 1541 Stars (树状数组)

Problem Description Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given

HDU 3854 Glorious Array(树状数组)

题意:给一些结点,每个结点是黑色或白色,并有一个权值.定义两个结点之间的距离为两个结点之间结点的最小权值当两个结点异色时,否则距离为无穷大.给出两种操作,一种是将某个结点改变颜色,另一个操作是询问当前距离小于K的结点有多少对,K是一个定值. 思路:先求最初时候小于k的结点有多少对,然后每次改变颜色的时候,统计该点左侧和右侧各有多少同色和异色的结点(这一步使用树状数组),分别处理就行.另外需要预处理离某个结点最近的两个距离小于K的结点的位置. 代码写的略乱. #include<cstdio> #