1036 [HEOI2012]采花 树状数组 离线操作 区间内出现两次以上数的数量

 链接:https://ac.nowcoder.com/acm/problem/20545
来源:牛客网

题目描述

萧芸斓是Z国的公主,平时的一大爱好是采花。
今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。
花园足够大,容纳了 nnn 朵花,花有 ccc 种颜色(用整数 1−c1-c1c 表示),且花是排成一排的,以便于公主采花。
公主每次采花后会统计采到的花的颜色数,颜色数越多她会越高兴!同时,她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵。为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花。
由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福涵洁综合各种因素拟定了 mmm 个行程,然后一一向你询问公主能采到多少朵花(她知道你是编程高手,定能快速给出答案!),最后会选择令公主最高兴的行程(为了拿到更多奖金!)。
 

输入描述:

第一行三个空格隔开的整数 n、cn、cnc 以及 mmm。
接下来一行 nnn 个空格隔开的整数,每个数在[1, c]间,第 iii 个数表示第 iii 朵花的颜色。
接下来 mmm 行每行两个空格隔开的整数 lll 和 r(l≤r)r(l ≤ r)rlr),表示女仆安排的行程为公主经过第 lll 到第 rrr 朵花进行采花。

输出描述:

mmm 行,每行一个整数,第 iii 个数表示公主在女仆的第 iii 个行程中能采到的花的颜色数。
示例1

输入

复制
5 3 5
1 2 2 3 1
1 5
1 2
2 2
2 3
3 5

输出

复制
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的花各一朵,公主不采。

备注:

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

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

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

对于全部的测试点,保证 1≤xi≤c1 \leq x_i \leq c1xic,1≤l≤r≤n1 \leq l \leq r \leq n1lrn。

分析

题意是一个区间内同一种花出现两次,就算是采到了一种花

感觉很难维护,因为每一种花都在不同位置,每一种花也不好确定在一个区间内出现过两次

但思考假如 同一种花,第一朵出现在 i 位置,第二朵出现在 j 位置,那对于左边界在[1,i] 右边界在 [j,n]内的所有区间,这种花都有一个贡献

可以维护每一种花第一次出现和第二次出现的位置,

考虑从左往右遍历,同时将所有查询离线操作按照右边界递增排序,每次找到一朵新的花,如果不是第一次出现,就在最近的一次出现 j 前面的区间[1,j] 内 +1,同时将上上次出现的位置k 前面的区间 [1,k] 内-1抵消上一次出现的 +1。

这样树状数组维护的就是 [1,j] 区间内每种花朵出现两次以上的次数。对于区间[l,r]出现两次以上次数的花,sum[r] - sum[l-1] 就是答案

//-------------------------代码----------------------------

//#define int ll
const int N = 2e6+10;
int n,m;

int a[N],tr[N],ans[N],pre[N][2];

struct node {
    int l,r,id;
    bool operator<(const node x)const {
        return r<x.r;
    }
}v[N];

void add(int x,int c) {
    for(int i = x;i<=n;i+=lowbit(i)) tr[i] += c;
}

int sum(int x) {
    int res = 0;for(int i = x;i;i-=lowbit(i)) res += tr[i];return res;
}


void solve()
{
    int w;
    cin>>n>>w>>m;
    fo(i,1,n) cin>>a[i];
    fo(i,1,m) {
        cin>>v[i].l >> v[i].r;v[i].id = i;
    }
    sort(v+1,v+1+m);
    for(int i = 1,j = 1;i<=n;i++) {
        if(pre[a[i]][0] == 0) {
            pre[a[i]][0] = i;
        } else if(pre[a[i]][1] == 0) {
            pre[a[i]][1] = i;
            add(pre[a[i]][0],1);
        } else {
            add(pre[a[i]][0],-1);
            add(pre[a[i]][1],1);
            pre[a[i]][0] = pre[a[i]][1];
            pre[a[i]][1] = i;
        }
        while(v[j].r == i)ans[v[j].id] = sum(v[j].r) - sum(v[j].l-1),j++;
    }
    fo(i,1,m) cout<<ans[i]<<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-11 02:36  er007  阅读(17)  评论(0编辑  收藏  举报