bzoj1878: [SDOI2009]HH的项链

莫队算法。

说白了就是乱搞。。。。。

这道题必须离线。

正解是树状数组,首先计算每个颜色第一个点构成的序列的答案。(每个颜色只有一个点,直接维护前缀和就可以了)。

然后询问按左端点排序,每回扫到一个点x,就在x的颜色的下一点的位置上+1。

这样俩个前缀和相减时,当且仅当(我一直觉得这四个字很newbee)区间里有某种颜色,答案+1。当然很多种颜色就很多个+1.

我直接莫队乱搞。第一次都没分块,直接排序就统计,好像还能拿60分。。。。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 50000 + 10;
const int maxm = 200000 + 10;
const int maxw = 1000000 + 10;
int pos[maxn];

struct Query {
    int l,r,id;
}q[maxm];

bool cmp (Query a,Query b) {
    if(pos[a.l]==pos[b.l]) return a.r<b.r;
    return a.l<b.l;
}
int m,n,a[maxn],cnt[maxw],res[maxm],ans,l,r,block;

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&m);    
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    block = (int) sqrt(n+0.5);
    for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
    sort(q+1,q+m+1,cmp);
    l=1; r=0;
    for(int i=1;i<=m;i++) {
        while(r<q[i].r) {
            r++;
            if(!cnt[a[r]]) ans++;    
            cnt[a[r]]++;
        }
        while(l<q[i].l) {
            if(cnt[a[l]]==1) ans--;    
            cnt[a[l]]--;
            l++;
        }
        while(l>q[i].l) {
            l--;
            if(!cnt[a[l]]) ans++;
            cnt[a[l]]++;
        }
        while(r>q[i].r) {
            if(cnt[a[r]]==1) ans--;
            cnt[a[r]]--;
            r--;
        }
        res[q[i].id]=ans;
    }
    for(int i=1;i<=m;i++) printf("%d\n",res[i]); 
    return 0;
}
posted @ 2016-06-01 16:12  invoid  阅读(193)  评论(0编辑  收藏  举报