出题人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
out1

相关文章: