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

Posted Lovaer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了查询区间内有多少个不同的数(线段树/树状数组)相关的知识,希望对你有一定的参考价值。

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

线段树版本(过了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 } 

 

以上是关于查询区间内有多少个不同的数(线段树/树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

gym344448C线段树/树状数组 离线查询区间小于等于k的数的数量

3155: Preprefix sum

线段树的思路

洛谷 3380 模板二逼平衡树(树状数组套权值线段树)

P3372 模板线段树 1(区间修改区间查询)(树状数组)

神犇求解…树状数组能求区间最值吗?时间复杂度是多少啊?…还有就是树状数组在求解啥问题上更有优势?