bzoj 3339 莫队
题意:
求任意一个区间的SG函数。
想到线段树,但是线段树合并很麻烦。
线段树——分块。
分块的一个应用就是莫队算法。
怎么暴力递推呢?
从一个区间到另一个区间,Ans 取决于 Ans 和 加入和删除的这个数的大小比较。加入一个新数,可能导致Ans 变大,变到哪里去呢? 用一个cnt记录出现数值的个数。
变大到cnt=0的地方。
减去一个数,可能导致Ans 变小。这时就要看cnt 和 大小比较了。
#include <bits/stdc++.h> using namespace std; const int maxn = 200011*41; int N,M; int a[maxn]; int pos[maxn]; int ans[maxn]; int cnt[maxn]; int Ans; struct Node { int l,r; int id; }nodes[maxn]; bool cmp(Node a,Node b) { if(pos[a.l]==pos[b.l]) return a.r < b.r; return pos[a.l] < pos[b.l]; } void add(int x) { cnt[x]++; if(Ans==x) while(cnt[Ans]) Ans++; } void del(int x) { cnt[x]--; if(cnt[x]==0&&x<Ans)Ans=x; } int main(int argc, char const *argv[]) { scanf("%d%d",&N,&M); int sz =ceil(sqrt(1.0*N)); for(int i=1; i <=N; i++) { scanf("%d",&a[i]); pos[i] = (i-1)/sz; } for(int i=1; i <= M; i++) { scanf("%d%d",&nodes[i].l,&nodes[i].r); nodes[i].id = i; } sort(nodes+1,nodes+1+M,cmp); int L = 1,R = 0; Ans = 0; for(int i=1;i<=M;i++) { int id = nodes[i].id; while(R<nodes[i].r)R++,add(a[R]); while(L>nodes[i].l)L--,add(a[L]); while(R>nodes[i].r)del(a[R]),R--; while(L<nodes[i].l)del(a[L]),L++; ans[id]=Ans; } for(int i=1; i <= M; i++) printf("%d\n", ans[i]); return 0; }