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");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值