采花
题目描述
萧芸斓是 Z国的公主,平时的一大爱好是采花。
今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。花园足够大,容纳了 n 朵花,花有 c 种颜色(用整数 1-c 表示) ,且花是排成一排的,以便于公主采花。
公主每次采花后会统计采到的花的颜色数, 颜色数越多她会越高兴! 同时, 她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵。为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花。 由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福涵洁综合各种因素拟定了 m 个行程,然后一一向你询问公主能采到多少朵花(她知道你是编程高手,定能快速给出答案! ) ,最后会选择令公主最高兴的行程(为了拿到更多奖金! ) 。
输入输出格式
输入格式:
第一行四个空格隔开的整数 n、c 以及 m。
接下来一行 n 个空格隔开的整数,每个数在[1, c]间,第i 个数表示第 i 朵花的颜色。
接下来 m 行每行两个空格隔开的整数 l 和 r(l ≤ r) ,表示女仆安排的行程为公主经过第 l 到第r 朵花进行采花。
输出格式:
共m行, 每行一个整数, 第i个数表示公主在女仆的第i个行程中能采到的花的颜色数。
输入输出样例
输入样例#1:
5 3 5 1 2 2 3 1 1 5 1 2 2 2 2 3 3 5
输出样例#1:
2 0 0 1 0
说明
对于100%的数据,1 ≤ n ≤10^5,c ≤ n,m ≤ 10^5。
用nxt[i]记录下一个颜色i出现的位置
考虑离线做法我们不断从左往右扫
因为有一种花有两个才有贡献
所以如果我们即将扫过i点如果nxt[nxt[i]]存在则将nxt[nxt[i]]的贡献加1
这样就变成了前缀和
树状数组就可以过了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Node 7 { 8 int l,r,num,ans; 9 }a[100001]; 10 int n,nxt[100001],p[100001],color[100001],cs[400001],c,m; 11 bool cmp(Node a,Node b) 12 { 13 return (a.l<b.l||(a.l==b.l&&a.r<b.r)); 14 } 15 bool cmp2(Node a,Node b) 16 { 17 return a.num<b.num; 18 } 19 void add(int x,int d) 20 { 21 while (x<=n) 22 { 23 cs[x]+=d; 24 x+=(x&(-x)); 25 } 26 } 27 int sum(int x) 28 {int s=0; 29 while (x) 30 { 31 s+=cs[x]; 32 x-=(x&(-x)); 33 } 34 return s; 35 } 36 int main() 37 {int i,j; 38 cin>>n>>c>>m; 39 for (i=1;i<=n;i++) 40 { 41 scanf("%d",&color[i]); 42 } 43 for (i=n;i>=1;i--) 44 nxt[i]=p[color[i]],p[color[i]]=i; 45 for (i=1;i<=c;i++) 46 if (p[i]&&nxt[p[i]]) add(nxt[p[i]],1); 47 for (i=1;i<=m;i++) 48 { 49 scanf("%d%d",&a[i].l,&a[i].r); 50 a[i].num=i; 51 } 52 sort(a+1,a+m+1,cmp); 53 j=1; 54 for (i=1;i<=m;i++) 55 { 56 while (j<a[i].l) 57 { 58 if (nxt[j]) add(nxt[j],-1); 59 if (nxt[j]&&nxt[nxt[j]]) add(nxt[nxt[j]],1); 60 j++; 61 } 62 a[i].ans=sum(a[i].r)-sum(a[i].l-1); 63 } 64 sort(a+1,a+m+1,cmp2); 65 for (i=1;i<=m;i++) 66 printf("%d\n",a[i].ans); 67 }