[BZOJ3236][Ahoi2013]作業:樹套樹/(分塊+莫隊)
阿新 • • 發佈:2018-12-12
分析
第一問隨便搞,直接說第二問。
令原數列為\(seq\),\(pre_i\)為\(seq_i\)這個值上一個出現的位置,於是可以簡化詢問條件為:
\(l \leq i \leq r\)
\(a \leq seq_i \leq b\)
\(pre_i < l\)
這是一個顯然的三維數點問題。發現第三維\(pre_i\)只有最大值的限制,所以我們可以把所有詢問按\(l\)升序排序,所有點按\(pre_i\)升序排序,用一個指標從左往右掃所有詢問,然後不斷向資料結構插入符合第三維要求的點,剩下的兩維樹狀陣列套權值線段樹解決。
然後就被卡空間了。
然後題解告訴我們可以莫隊+分塊解決。
\(FAQ\)
程式碼
樹套樹(MLE)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <cctype> #include <algorithm> #define lowbit(x) ((x)&(-(x))) #define rin(i,a,b) for(int i=(a);i<=(b);i++) #define rec(i,a,b) for(int i=(a);i>=(b);i--) #define trav(i,x) for(int i=head[(x)];i;i=e[i].nxt) using std::cin; using std::cout; using std::endl; typedef long long LL; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } const int MAXN=100005; const int MAXM=1000005; int n,m,siz,tot,a[MAXN],b[MAXN],pre[MAXN],las[MAXN]; int ans1[MAXM],ans2[MAXM]; int loc,ql,qr,root[MAXN],lc[MAXN*400],rc[MAXN*400],sum[MAXN*400]; struct Po{ int pos,val,pre; inline friend bool operator < (Po x,Po y){return x.pre<y.pre;} }p[MAXN]; struct Qu{ int l,r,a,b,id; inline friend bool operator < (Qu x,Qu y){return x.l<y.l;} }q[MAXM]; #define mid ((l+r)>>1) int upd(int pre,int l,int r){ int o=++tot;lc[o]=lc[pre],rc[o]=rc[pre],sum[o]=sum[pre]+1; if(l==r) return o; if(loc<=mid) lc[o]=upd(lc[pre],l,mid); else rc[o]=upd(rc[pre],mid+1,r); return o; } int query(int o,int l,int r){ if(ql>qr) return 0; if(ql<=l&&r<=qr) return sum[o]; int ret=0; if(mid>=ql) ret+=query(lc[o],l,mid); if(mid<qr) ret+=query(rc[o],mid+1,r); return ret; } int query(int u,int v,int l,int r){ if(ql>qr) return 0; if(ql<=l&&r<=qr) return sum[v]-sum[u]; int ret=0; if(mid>=ql) ret+=query(lc[u],lc[v],l,mid); if(mid<qr) ret+=query(rc[u],rc[v],mid+1,r); return ret; } #undef mid inline void Add(int pos,int val){ loc=val; for(int i=pos;i<=n;i+=lowbit(i)) root[i]=upd(root[i],1,siz); } inline int Ask(int x){ if(ql>qr) return 0; int ret=0; for(int i=x;i;i-=lowbit(i)) ret+=query(root[i],1,siz); return ret; } inline int Ask(int l,int r,int lval,int rval){ ql=lval,qr=rval; if(ql>qr) return 0; return Ask(r)-Ask(l-1); } int main(){ n=read(),m=read(); rin(i,1,n) b[i]=a[i]=read(); std::sort(b+1,b+n+1); siz=std::unique(b+1,b+n+1)-b-1; rin(i,1,n) a[i]=std::lower_bound(b+1,b+siz+1,a[i])-b; rin(i,1,n){pre[i]=las[a[i]];las[a[i]]=i;p[i]=(Po){i,a[i],pre[i]};} rin(i,1,m){q[i].l=read(),q[i].r=read(),q[i].a=std::lower_bound(b+1,b+siz+1,read())-b,q[i].b=std::upper_bound(b+1,b+siz+1,read())-b-1,q[i].id=i;} rin(i,1,n){loc=a[i];root[i]=upd(root[i-1],1,siz);} rin(i,1,m){ql=q[i].a,qr=q[i].b;ans1[i]=query(root[q[i].l-1],root[q[i].r],1,siz);} tot=0;memset(root,0,sizeof root);std::sort(p+1,p+n+1);std::sort(q+1,q+m+1); int pptr=1,qptr=1; while(pptr<=n&&!p[pptr].pre){Add(p[pptr].pos,p[pptr].val);pptr++;} rin(i,1,n){ while(qptr<=m&&q[qptr].l==i){ans2[q[qptr].id]=Ask(q[qptr].l,q[qptr].r,q[qptr].a,q[qptr].b);qptr++;} while(pptr<=n&&p[pptr].pre==i){Add(p[pptr].pos,p[pptr].val);pptr++;} } rin(i,1,m) printf("%d %d\n",ans1[i],ans2[i]); return 0; }
莫隊+分塊
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <cctype> #include <algorithm> #define rin(i,a,b) for(int i=(a);i<=(b);i++) #define rec(i,a,b) for(int i=(a);i>=(b);i--) #define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt) using std::cin; using std::cout; using std::endl; typedef long long LL; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } const int MAXN=100005; const int MAXM=1000005; const int SIZE=345; int n,m,siz,ret1,ret2,a[MAXN],b[MAXN],blg[MAXN],cnt[MAXN],sum1[SIZE],sum2[SIZE],ans1[MAXM],ans2[MAXM]; struct Qu{ int l,r,lk,a,b,id; inline friend bool operator < (Qu x,Qu y){ if(x.lk!=y.lk) return x.lk<y.lk; if(x.lk&1) return x.r<y.r; else return x.r>y.r; } }q[MAXM]; inline void query(int l,int r){ ret1=ret2=0; rin(i,blg[l]+1,blg[r]-1) ret1+=sum1[i],ret2+=sum2[i]; int lim=std::min(blg[l]*SIZE,r);rin(i,l,lim) ret1+=cnt[i],ret2+=(cnt[i]>0); if(blg[l]!=blg[r]) rin(i,(blg[r]-1)*SIZE+1,r) ret1+=cnt[i],ret2+=(cnt[i]>0); } int main(){ n=read(),m=read(); rin(i,1,n) a[i]=b[i]=read(); std::sort(b+1,b+n+1);siz=std::unique(b+1,b+n+1)-b-1; rin(i,1,n){a[i]=std::lower_bound(b+1,b+siz+1,a[i])-b;blg[i]=(i-1)/SIZE+1;}; rin(i,1,m){q[i].l=read(),q[i].r=read(),q[i].a=std::lower_bound(b+1,b+siz+1,read())-b,q[i].b=std::upper_bound(b+1,b+siz+1,read())-b-1,q[i].lk=(q[i].l-1)/SIZE+1;q[i].id=i;} std::sort(q+1,q+m+1); int l=1,r=0; rin(i,1,m){ if(q[i].a>q[i].b) continue; while(l>q[i].l){l--;cnt[a[l]]++;sum1[blg[a[l]]]++;if(cnt[a[l]]==1)sum2[blg[a[l]]]++;} while(r<q[i].r){r++;cnt[a[r]]++;sum1[blg[a[r]]]++;if(cnt[a[r]]==1)sum2[blg[a[r]]]++;} while(l<q[i].l){cnt[a[l]]--;sum1[blg[a[l]]]--;if(cnt[a[l]]==0)sum2[blg[a[l]]]--;l++;} while(r>q[i].r){cnt[a[r]]--;sum1[blg[a[r]]]--;if(cnt[a[r]]==0)sum2[blg[a[r]]]--;r--;} query(q[i].a,q[i].b);ans1[q[i].id]=ret1;ans2[q[i].id]=ret2; } rin(i,1,m) printf("%d %d\n",ans1[i],ans2[i]); return 0; }