【题解】LuoGu4113:[HEOI2012]采花

版权声明:Fashion Education https://blog.csdn.net/ModestCoder_/article/details/82596047

原题传送门
@BZOJ
Description
萧芸斓是Z国的公主,平时的一大爱好是采花。今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花
。花园足够大,容纳了n朵花,花有c种颜色(用整数1-c表示),且花是排成一排的,以便于公主采花。公主每次
采花后会统计采到的花的颜色数,颜色数越多她会越高兴!同时,她有一癖好,她不允许最后自己采到的花中,某
一颜色的花只有一朵。为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必
能再次采到此颜色的花。由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福涵
洁综合各种因素拟定了m个行程,然后一一向你询问公主能采到多少朵花(她知道你是编程高手,定能快速给出答
案!),最后会选择令公主最高兴的行程(为了拿到更多奖金!)。
Input
第一行四个空格隔开的整数n、c以及m。
接下来一行n个空格隔开的整数,每个数在[1, c]间,第i个数表示第i朵花的颜色。
接下来m行每行两个空格隔开的整数l和r(l ≤ r),表示女仆安排的行程为公主经过第l到第r朵花进行采花。
Output
共m行,每行一个整数,第i个数表示公主在女仆的第i个行程中能采到的花的颜色数。
Sample Input
5 3 5
1 2 2 3 1
1 5
1 2
2 2
2 3
3 5
Sample Output
2
0
0
1
0
【样例说明】

询问[1, 5]:公主采颜色为1和2的花,由于颜色3的花只有一朵,公主不采;询问[1, 2]:颜色1和颜色2的花均只有一朵,公主不采;

询问[2, 2]:颜色2的花只有一朵,公主不采;

询问[2, 3]:由于颜色2的花有两朵,公主采颜色2的花;

询问[3, 5]:颜色1、2、3的花各一朵,公主不采。

HINT
【数据范围】

对于100%的数据, 1 n 10 6 c n m 10 6

【题解】
因为我最近在练莫队,所以这道题一眼看过就码了个莫队,然后愉快地Tle了。。
看到这道题的数据范围,发现莫队是不行的,看题解发现了一种树状数组的玩法。

然后我一直用pascal捣鼓,结果一直wa得只有10分,实在是找不出问题。
不过我今天突然想到可以用c++搞一搞,结果就真的过了。

思路
用Next[i]表示与第i朵花颜色相同的下一朵花的位置
发现:一段区间内,从左到右第二次出现的颜色对ans产生贡献,所以可以用树状数组维护前缀和。
那么Next就是用于快速得到某一段区间的第二次出现的颜色

对于查询则是用离线

LuoGu加强数据后最后一个点一直Tle,加了氧气才过掉了,不过原始数据我的程序还是跑的过的,BZOJ里也ac了

Code:

#include <bits/stdc++.h>
using namespace std;
#define res register int
#define maxn 2000010
#define inf 2147483647
struct node{
    int l,r,id,ans;
};
node q[maxn];
int Next[maxn],color[maxn],p[maxn],n,m,c,tree[maxn];

inline int read(){
    int s = 0, w = 1;
    char c = getchar();
    while (c < '0' || c > '9'){
        if (c == '-') w = -1; c = getchar();
    }
    while (c >= '0' && c <= '9') s = (s << 3) + (s << 1) + (c ^ 48), c = getchar();
    return s * w;
}
inline bool cmp1(node x, node y){return x.l == y.l ? x.r < y.r : x.l < y.l;}
inline bool cmp2(node x, node y){return x.id < y.id;}
inline void add(int x, int y){for (; x <= n; x += (x & (-x))) tree[x] += y;}
inline int query(int x){int sum = 0; for (; x > 0; x -= (x & (-x))) sum += tree[x]; return sum;}
int main(){
    n = read(), c = read(), m = read();
    for (res i = 1; i <= n; ++i) color[i] = read();
    for (res i = n; i > 0; --i) Next[i] = p[color[i]], p[color[i]] = i;
    for (res i = 1; i <= c; ++i) if (p[i] && Next[p[i]]) add(Next[p[i]], 1);
    for (res i = 1; i <= m; ++i) q[i].l = read(), q[i].r = read(), q[i].id = i;
    sort(q + 1, q + 1 + m, cmp1);
    int l = 1;
    for (res i = 1; i <= m; ++i){
        for (; l < q[i].l; ++l){
            if (Next[l]) add(Next[l], -1);
            if (Next[l] && Next[Next[l]]) add(Next[Next[l]], 1);
        }
        q[i].ans = query(q[i].r) - query(q[i].l - 1);
    }
    sort(q + 1, q + 1 + m, cmp2);
    for (res i = 1; i <= m; ++i) printf("%d\n", q[i].ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/82596047