BZOJ2743: 采花 题解

一眼看上去像莫队,但是范围是1e6, O(nn) O ( n n ) 会炸
考虑离线以后用数据结构维护
其实这种技巧挺常见的,就是将询问按照右端点排序
然后枚举右端点,从右向左移动,每移动一个维护每种颜色从右向左数第二个在哪里,因为每次只会修改一种颜色,这个是很好维护的
用树状数组维护所有的颜色的“第二个”的位置的出现次数,那么对于查询[l,r],我显然要找从右向左数第二个在l之后的那些颜色,也就是求(l,r)中的个数之和

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=100003;
const LL LINF=2e16;
const int INF=1e9;
const int magic=348;
const double eps=1e-10;
const double pi=acos(-1);

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

int n,c,m;
int a[1000048],last[1000048],pos[1000048],cur[1000048];
int ans[1000048];

struct Query
{
    int left,right,ind;
    inline bool operator < (const Query &x) const {return right>x.right;}
}q[1000048];

namespace BIT
{
    int c[1000048];
    inline void init() {for (register int i=1;i<=n;i++) c[i]=0;}
    inline void update(int x,int delta) {while (x<=n) {c[x]+=delta;x+=LOWBIT(x);}}
    inline int query(int x) {int res=0;while (x) {res+=c[x];x-=LOWBIT(x);}return res;}
    inline int calc(int left,int right) {return query(right)-query(left-1);}
}

int main ()
{
    int i;n=getint();c=getint();m=getint();
    for (i=1;i<=n;i++) a[i]=getint(),last[i]=pos[a[i]],pos[a[i]]=i;
    for (i=1;i<=m;i++) q[i].left=getint(),q[i].right=getint(),q[i].ind=i;
    sort(q+1,q+m+1);BIT::init();
    for (i=1;i<=c;i++) {cur[i]=pos[i];if (last[cur[i]]) BIT::update(last[cur[i]],1);}
    int pt=1;
    for (i=n;i>=1;i--)
    {
        if (i!=n)
        {
            if (last[cur[a[i+1]]]) BIT::update(last[cur[a[i+1]]],-1);
            cur[a[i+1]]=last[cur[a[i+1]]];
            if (last[cur[a[i+1]]]) BIT::update(last[cur[a[i+1]]],1);
        }
        while (pt<=m && q[pt].right==i) ans[q[pt].ind]=BIT::calc(q[pt].left,n),pt++;
    }
    for (i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

你可能感兴趣的:(树状数组)