查询区间内有多少个不同的数(线段树/树状数组)

入门级数据结构算法。复习一下,分别手写一个。

线段树版本(过了CF上的https://codeforces.com/contest/1291/problem/D):

 1 #include<bits/stdc++.h>
 2 #define f(i,a,b) for(int i=a;i<=b;i++)
 3 using namespace std;
 4 struct qujian{
 5     int l,r,index;
 6     friend bool operator < (const qujian q1,const qujian q2){
 7         return q1.r<q2.r;
 8     }
 9 }qu[100005];
10 int q;
11
12 const int N=2e5+5;
13 int a[N];
14 struct node{
15     int l,r,val;
16 }tree[N<<2];
17 void build(int rt,int l,int r){
18     tree[rt].l=l,tree[rt].r=r;
19     if(l==r){
20         tree[rt].val=0;
21         return;
22     }
23     int mid=l+r>>1;
24     build(rt<<1,l,mid);
25     build(rt<<1|1,mid+1,r);
26     tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val;
27 }
28 void update(int rt,int pos,int val){
29     if(tree[rt].l==tree[rt].r&&pos==tree[rt].l){
30         tree[rt].val+=val;
31         return;
32     }
33     int mid=tree[rt].l+tree[rt].r>>1;
34     if(pos<=mid) update(rt<<1,pos,val);
35     else update(rt<<1|1,pos,val);
36     tree[rt].val+=val;
37 }
38 int query(int rt,int l,int r){
39     if(l<=tree[rt].l&&r>=tree[rt].r) return tree[rt].val;
40     int mid=tree[rt].l+tree[rt].r>>1;
41     if(l>mid) return query(rt<<1|1,l,r);
42     else if(r<=mid) return query(rt<<1,l,r);
43     else return query(rt<<1,l,mid)+query(rt<<1|1,mid+1,r);
44 }
45
46 map<char,int> mp;
47 char b[N];
48 int ans[N];
49
50 bool cmp(const qujian q1,const qujian q2){
51     return q1.index<q2.index;
52 }
53
54 int main(){
55     scanf("%s",b+1);
56     int len=strlen(b+1);
57     scanf("%d",&q);
58     f(i,1,q) scanf("%d%d",&qu[i].l,&qu[i].r),qu[i].index=i;
59     sort(qu+1,qu+1+q);
60     //f(i,1,q) cout<<qu[i].l<<" "<<qu[i].r<<endl;
61     int cur=1;
62     build(1,1,len);
63     f(i,1,q){
64         f(j,cur,qu[i].r){
65             //cout<<"the current qujian is "<<qu[i].l<<" "<<qu[i].r<<endl;
66             int p=mp[b[j]];
67             if(p!=0){
68                 update(1,p,-1);
69                 //cout<<b[j]<<" has appeared at "<<p<<endl;
70             }
71             update(1,j,1);
72             //cout<<b[j]<<" last appeared at "<<j<<endl;
73             //cout<<"now the "<<j<<" is "<<query(1,j,j)<<endl;
74             mp[b[j]]=j;
75         }
76         cur=qu[i].r+1;
77         ans[qu[i].index]=query(1,qu[i].l,qu[i].r);
78         //cout<<qu[i].index<<":["<<qu[i].l<<","<<qu[i].r<<"]="<<query(1,qu[i].l,qu[i].r)<<endl;
79     }
80     //f(i,1,q) cout<<ans[i]<<" ";
81     sort(qu+1,qu+1+q,cmp);
82     f(i,1,q){
83         if(qu[i].r-qu[i].l+1==1){
84             puts("YES");
85         }
86         else if(ans[i]>=3){
87             puts("YES");
88         }
89         else if(b[qu[i].l]!=b[qu[i].r]){
90             puts("YES");
91         }
92         else puts("NO");
93     }
94 } 

树状数组版本(怪不得潘神这么喜欢,写起来确实短得多):

 1 #include<bits/stdc++.h>
 2 #define f(i,a,b) for(int i=a;i<=b;i++)
 3 using namespace std;
 4 struct qujian{
 5     int l,r,index;
 6     friend bool operator < (const qujian q1,const qujian q2){
 7         return q1.r<q2.r;
 8     }
 9 }qu[100005];
10 bool cmp(const qujian q1,const qujian q2){
11     return q1.index<q2.index;
12 }
13 const int N=1e5+5;
14 map<int,int> mp;
15 int ans[N];
16 int len[N];
17 int n,q;
18 int a[N];
19 int tree[N];
20 #define lowbit(x) (x&(-x))
21 void update(int pos,int val){
22     while(pos<=n){
23         tree[pos]+=val;
24         pos+=lowbit(pos);
25     }
26 }
27 int sum_1_to_pos(int pos){
28     int ans=0;
29     while(pos>0){
30         ans+=tree[pos];
31         pos-=lowbit(pos);
32     }
33     return ans;
34 }
35 #define query(x,y) (sum_1_to_pos(y)-sum_1_to_pos(x-1))
36
37 int main(){
38     scanf("%d%d",&n,&q);
39     f(i,1,n) scanf("%d",&a[i]);
40     f(i,1,q) scanf("%d%d",&qu[i].l,&qu[i].r),qu[i].index=i,len[i]=qu[i].r-qu[i].l+1;
41     sort(qu+1,qu+1+q);
42     int cur=1;
43     f(i,1,q){
44         f(j,cur,qu[i].r){
45             int p=mp[a[j]];
46             if(p!=0){
47                 update(p,-1);
48             }
49             update(j,1);
50             mp[a[j]]=j;
51         }
52         cur=qu[i].r+1;
53         ans[qu[i].index]=query(qu[i].l,qu[i].r);
54     }
55     f(i,1,q){
56         if(ans[i]==len[i]) puts("Yes");
57         else puts("No");
58     }
59 } 

原文地址:https://www.cnblogs.com/St-Lovaer/p/12261657.html

时间: 2024-10-16 02:44:38

查询区间内有多少个不同的数(线段树/树状数组)的相关文章

POJ 2761-Feed the dogs(划分树)求区间内第k小的数

Feed the dogs Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 17679   Accepted: 5561 Description Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but not the

【大杀器】利用划分树秒杀区间内第k大的数

最近看了一道题,大概就是给出一个序列,不断询问其子区间内第k大的数,下面是个截图 绕了一圈没找到中文版题目,if(你是大佬) then 去看截图:else{我来解释:给出一个整数n,和一个整数m,分别表示序列元素个数和询问次数,然后输入n个数和m个询问,每个询问包含3个数,分别是区间起止点(l和r)和k,求出区间内第k大的数并输出:}这是一道很简单的模板题,怎么解决呢?小编最初想到的是打暴力,正所谓暴力出奇迹,说不定可以成功,反正不会优化,先试试吧,直接把规定区间[l,r]排一次序了,然后在查找

2017乌鲁木齐区域赛K(容斥原理【求指定区间内与n互素的数的个数】)

#include<bits/stdc++.h>using namespace std;const long long mod = 998244353;typedef const long long ll;vector<long long>p;long long inv(long long x,long long y)//快速幂求逆元模板(以乘代除){    long long r=1;    while(y>0)    {        if(y&1)        

【hdu5381】维护区间内所有子区间的gcd之和-线段树

题意:给定n个数,m个询问,每次询问一个区间内所有连续子区间的gcd的和.n,m<=10^5 题解: 这题和之前比赛的一题很像.我们从小到大枚举r,固定右端点枚举左端点,维护的区间最多只有log段.为什么?以为长区间的gcd肯定是短区间gcd的约数,并且要是不同的话至少要/2,最多那就只有log数值这么多段.还有,相同gcd的区间一定是连续的若干个(想想gcd是怎么求的就知道了).线段树每个端点x维护的是以x为左端点,r从1到当前的r的gcd的和.链表维护log段数,然后每次加到线段树里更新.

hdu 1806 Frequent values(给定一个非降序数组,求任意区间内出现次数最多的数的次数)

1.题目解析可见<训练指南>P198 2代码: #include<cstdio> #include<cstring> #include<cmath> #define Min(a,b) ((a)<(b)?(a):(b)) #define Max(a,b) ((a)>(b)?(a):(b)) #define N 100005 #define INF 1<<30 using namespace std; int a[N]; int valu

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

HDU 4135 Co-prime 区间内与n互质的个数 容斥(入门

题目链接:点击打开链接 题意:给定区间[l, r] 询问区间内有多少个数和n互质 思路: solve(x) 表示[1,x]区间内与n互质的个数,则ans = solve(r)-solve(l-1); 与n互质的个数=所有数-与n不互质的数=所有数-(与n有一个因子-与n有2个因子的+与n有3个因子的) 状压n的因子个数,然后根据上面的公式容斥得到. #include <stdio.h> #include <iostream> #include <algorithm> #

HDU4135 (求a~b内与n互素的数的个数) 容斥原理

掌握了容斥原理后,便会发现,这是一道简单的容斥原理的题. 题目描述:给定A, B, N (1 <= A <= B <= 10^15,1<=N <= 10^9).求[A,B]区间内与N互素的数的个数 步骤: (1)将问题化为求1~B,1~A中与N互素的数的个数的差,当然考虑到A可能与N互素的情况,在实际操作时, 即求1~A时最好改成求1~A-1(包含A-1): (2)求N的质因子(可参考:http://blog.csdn.net/yzj577/article/details/3

CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树

求两个数列的子列的交集 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1104 Description 给两个数列A, B,长度分别为n1, n2,保证A中每个元素互不相同,保证B中每个元素互不相同..进行Q次询问,每次查找A[l1...r1]和B[l2..r2]的交集 集合 大小是多少.. 比如 A = {1,2,3,4,5,6,7},B = {7,6,5,4,3,2,1}