Luogu4113 [HEOI2012]采花

原题链接:https://www.luogu.com.cn/problem/P4113

采花

题目描述

萧薰儿是古国的公主,平时的一大爱好是采花。

今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。

花园足够大,容纳了 n n n 朵花,共有 c c c 种颜色,用整数 1 ∼ c 1 \sim c 1c 表示。且花是排成一排的,以便于公主采花。公主每次采花后会统计采到的花的颜色数,颜色数越多她会越高兴。同时,她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵。为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花。

由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福涵洁综合各种因素拟定了 m m m 个行程,然后一一向你询问公主能采到的花共有几种不同的颜色。

输入格式

输入的第一行是三个用空格隔开的整数,分别代表花的个数 n n n,花的颜色数 c c c,以及行程数 m m m

输入的第二行是 n n n 个用空格隔开的整数,第 i i i 个整数代表第 i i i 朵花的颜色 x i x_i xi

3 3 3 行到第 ( m + 2 ) (m + 2) (m+2) 行,每行两个整数 l , r l, r l,r,第 ( i + 2 ) (i + 2) (i+2) 行的数字代表第 i i i 次行程为第 l l l 到第 r r r 朵花。

输出格式

共输出 m m m 行,每行一个整数。第 i i i 行的整数代表第 i 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

说明/提示

输入输出样例 1 1 1 解释

共有五朵花,颜色分别为 1 ,   2 ,   2 ,   3 ,   1 1,~2,~2,~3,~1 1, 2, 2, 3, 1

对于第一次行程,公主采花的区间为 [ 1 , 5 ] [1, 5] [1,5],可以采位置 1 ,   2 ,   3 ,   5 1,~2,~3,~5 1, 2, 3, 5 处的花,共有 1 1 1 2 2 2 两种不同的颜色。

对于第二次行程,公主采花的区间为 [ 1 , 2 ] [1, 2] [1,2],但是颜色为 1 1 1 2 2 2 的花都只出现了一次,因此公主无花可采。

对于第三次行程,公主采花的区间为 [ 2 , 2 ] [2, 2] [2,2],但是颜色为 2 2 2 的花只出现了一次,公主无花可采。

对于第四次行程,公主采花的区间为 [ 2 , 3 ] [2, 3] [2,3],可以采 2 ,   3 2,~3 2, 3 位置的花,只有 2 2 2 这一种颜色。

对于第五次行程,公主采花的区间为 [ 3 , 5 ] [3,5] [3,5],但是颜色为 1 , 2 , 3 1, 2, 3 1,2,3 的花都只出现了一次,因此公主无花可采。

数据范围与约定

本题采用多测试点捆绑测试,共有两个子任务。

对于子任务 1 1 1,分值为 100 100 100 分,保证 1 ≤ n , c , m ≤ 3 × 1 0 5 1 \leq n, c, m \leq 3 \times 10^5 1n,c,m3×105

对于子任务 2 2 2,分值为 100 100 100 分,保证 1 ≤ n , c , m ≤ 2 × 1 0 6 1 \leq n, c, m \leq 2 \times 10^6 1n,c,m2×106

对于全部的测试点,保证 1 ≤ x i ≤ c 1 \leq x_i \leq c 1xic 1 ≤ l ≤ r ≤ n 1 \leq l \leq r \leq n 1lrn

题解

HH的项链升级版,鉴于之前写的题解比较水,今天就赎一下罪。

首先依然是把所有询问离线,按照右端点排序,之后按顺序处理每一个询问。因为题目要求每个颜色出现两次,我们用 l s t 1 [ i ] lst1[i] lst1[i]记录颜色 i i i上一次出现的位置、 l s t 2 [ i ] lst2[i] lst2[i]记录颜色 i i i上上次出现的位置。如果这两个数组记录的都不为空,那么这个颜色一定出现了两次,我们就在树状数组里给该颜色上上次出现的位置加上 1 1 1,比如对于 1 ,   2 ,   2 ,   3 ,   1 ,   2 1,~2,~2,~3,~1,~2 1, 2, 2, 3, 1, 2,树状数组维护的序列变化情况就应该如下所示:
{ 0 } → { 0 , 0 } → { 0 , 1 , 0 } → { 0 , 1 , 0 , 0 } → { 1 , 1 , 0 , 0 , 0 } → { 1 , 0 , 1 , 0 , 0 , 0 } \{0\}\to\{0,0\}\to\{0,1,0\}\to\{0,1,0,0\}\to\{1,1,0,0,0\}\to\{1,0,1,0,0,0\} { 0}{ 0,0}{ 0,1,0}{ 0,1,0,0}{ 1,1,0,0,0}{ 1,0,1,0,0,0}

随时随地只有上上次出现该颜色的位置为 1 1 1就保证了当我们按照右端点升序的方式处理询问区间的时候,如果区间里有 1 1 1,那么该颜色一定在区间里出现了复数次。

代码

这钵啊,这钵是其他部分一次对,一个sort错两次……

码风放飞自我系列:

#include<bits/stdc++.h>
#define lb(v) (v&(-v))
using namespace std;
const int M=2e6+5;
int n,c,m,col[M],lst1[M],lst2[M],tree[M],ans[M];
struct Ask{
    
    int id,le,ri;}ask[M];
bool cmp(Ask a,Ask b){
    
    return a.ri==b.ri?a.le<b.le:a.ri<b.ri;}
void add(int v,int delta){
    
    for(;v&&v<=n;v+=lb(v))tree[v]+=delta;}
int sum(int v){
    
    int r=0;for(;v;v-=lb(v))r+=tree[v];return r;}
void in()
{
    
    
    scanf("%d%d%d",&n,&c,&m);
    for(int i=1;i<=n;++i)scanf("%d",&col[i]);
    for(int i=1;i<=m;++i)scanf("%d%d",&ask[i].le,&ask[i].ri),ask[i].id=i;
}
void ac()
{
    
    
    sort(ask+1,ask+m+1,cmp);
    for(int i=1,p=1;i<=m;ans[ask[i].id]=sum(ask[i].ri)-sum(ask[i].le-1),++i)
    for(;p<=ask[i].ri;lst1[col[p]]=p,++p)
    if(lst1[col[p]])add(lst2[col[p]],-1),add(lst2[col[p]]=lst1[col[p]],1);
    for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
}
int main()
{
    
    
    in(),ac();
    system("pause");
}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/113551774