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; }