出题人yjy
Description
ZJK 给你一个长度为 n 的数列和 m 次询问,每次询问从第 l 个到第 r 个数中,数 x 出现
了多少次。
Input
第一行一个整数 n,
第二行 n 个整数,表示这个数列。
第三行一个整数 m,表示询问数。
下面 m 行,每行三个整数 l, r, x,表示询问[l, r]之间数 x 出现的次数
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开,一共 m 行。
Example
6
1 1 2 3 3 1
8
1 6 1
3 5 3
3 5 2
2 6 1
1 3 3
2 6 3
2 6 4
1 6 2
3
2
1
2
0
2
0
1
Hint
涉及到的数列中所有数 x∈[1, 200000]
序列长度 n <= 100000
询问数 m <= 100000
注意:询问中有可能会询问不存在的数,但一定满足 x ∈ [1, 200000]
主席树板子嘛,比 第k大值 得板子还板子,至于主席树,有空再补一篇吧
add维护数出现的个数,n的范围20w,不用离散化
查询的时候,就一直查询,直到查询到叶节点,然后两点做差
ps:n不是树的大小范围,挂在这里(;′⌒`)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=200010; 7 int n,m,root[MAXN],cut,a[MAXN],s[MAXN]; 8 struct data 9 { 10 int lc,rc,ans; 11 }tree[MAXN*20]; 12 void add(int &now,int last,int l,int r,int x) 13 { 14 now=++cut; 15 tree[now].ans=tree[last].ans+1; 16 17 if(l==r) return ; 18 tree[now].lc=tree[last].lc; 19 tree[now].rc=tree[last].rc; 20 int mid=(l+r)>>1; 21 if(x<=mid) add(tree[now].lc,tree[last].lc,l,mid,x); 22 else add(tree[now].rc,tree[last].rc,mid+1,r,x); 23 } 24 int query(int L,int R,int l,int r,int x) 25 { 26 if(l==r)return tree[L].ans-tree[R].ans; 27 int mid=(l+r)>>1; 28 if(x<=mid)return query(tree[L].lc,tree[R].lc,l,mid,x); 29 else return query(tree[L].rc,tree[R].rc,mid+1,r,x); 30 } 31 int main() 32 { 33 int x,y,z,p=0; 34 scanf("%d",&n); 35 for(int i=1;i<=n;++i) 36 { 37 scanf("%d",&a[i]); 38 p=max(p,a[i]); 39 } 40 for(int i=1;i<=n;++i) 41 add(root[i],root[i-1],1,p,a[i]); 42 scanf("%d",&m); 43 while(m--) 44 { 45 scanf("%d%d%d",&x,&y,&z); 46 if(z>p) { 47 printf("0\n"); 48 continue; 49 } 50 printf("%d\n",query(root[y],root[x-1],1,p,z)); 51 } 52 return 0; 53 }
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0