1. 程式人生 > >[HEOI2012]採花

[HEOI2012]採花

第一眼以為是樹套樹qwq
然而n,m<=1e6
記上一個與i顏色相同的位置為nxt[i]
考慮i和nxt[i]會對那些詢問產生貢獻。
發現當右端點R>=i時,
左端點只要滿足nxt[nxt[i]]<l<=nxt[i]就會得到i的貢獻。
由此
把詢問按照R排序
掃描每一個點,對區間 ( nxt[nxt[i]] , nxt[i] ] 加一,查詢時查詢L位置的值即可。
實現可以用樹狀陣列維護差分序列實現。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define N 4400000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline int read()
{
    char ch=0;
    int x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
int n,k,m,l[N],f[N],ans[N];
struct node
{
    int l,r,id;
}p[N];
bool cmp(node a,node b)
{
    return a.r<b.r;
}
int s[N];
void add(int x,int num)
{
    for(;x<=n;x+=((x)&(-x)))s[x]+=num;
}
int query(int x)
{
    int ans=0;
    for(;x;x-=((x)&(-x)))ans+=s[x];
    return ans;
}
int main()
{
    int x,i,j;
    n=read();k=read();m=read();
    for(i=1;i<=n;i++)
    {
        x=read(); 
        l[i]=f[x];f[x]=i;
    }
    for(i=1;i<=m;i++)
    {
        p[i].id=i;
        p[i].l=read();
        p[i].r=read();
    }
    sort(p+1,p+m+1,cmp);
    for(i=1,j=0;i<=m;i++)
    {
        while(j<n&&j<p[i].r)
        {
            j++;
            if(!l[j])continue;
            add(l[l[j]]+1,+1);
            add(l[j]+1,-1);
        }
        ans[p[i].id]=query(p[i].l);
    }
    for(i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}