[bzoj 4939][Ynoi 2016]掉進兔子洞
阿新 • • 發佈:2018-12-27
傳送門
Description
一個長為 n 的序列 a。
有 m 個詢問,每次詢問三個區間,把三個區間中同時出現的數一個一個刪掉,問最後三個區間剩下的數的個數和,詢問獨立。
注意這裡刪掉指的是一個一個刪,不是把等於這個值的數直接刪完,
比如三個區間是 [1,2,2,3,3,3,3] , [1,2,2,3,3,3,3] 與 [1,1,2,3,3],就一起扔掉了 1 個 1,1 個 2,2 個 3。
Solution
弱化版是luoguP3674,這裡放上它的題解 戳我
要找相同的元素就是集合求交集,莫隊+bitset即可
可是這道題是要算上重複的元素的,很簡單,離散化的時候給每個數留下相應的空位就行了
即每個數的離散值等於小於它的數個數+1.
幾個例子:
我們把序列
3 3 5 5 6 7 7
,離散化成1 1 3 3 5 6 6
,而不是1 1 2 2 3 4 4
那麼,我們在加入數的時候,把它加到“它的離散值+它出現的次數-1”這個位置上
那麼求交就是
now.count()
還有一個問題,維護\(100000*100000\)的bitset!雖然看上去不太可能,但其實上我們分成3次莫隊就行了
Code
#include<bits/stdc++.h> #define min(a,b) ((a)<(b)?(a):(b)) 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; } #define MN 100005 int n,m,a[MN],T,nums[MN]; std::bitset<MN> now; std::bitset<MN> quer[33343]; struct ques{ int l,r,id,pl; bool operator <(const ques&o)const{return (pl^o.pl)?(pl<o.pl):((pl&1)?r<o.r:r>o.r);} }q[MN+33343]; int num[MN],len[MN]; inline void solve(int L,int R) { if(L>R) return; register int tt=0,i; for(i=1;i<=R-L+1;++i) { quer[i].set(); q[++tt].l=read(),q[tt].r=read();q[tt].pl=(q[tt].l-1)/T+1;q[tt].id=i;len[i] =q[tt].r-q[tt].l+1; q[++tt].l=read(),q[tt].r=read();q[tt].pl=(q[tt].l-1)/T+1;q[tt].id=i;len[i]+=q[tt].r-q[tt].l+1; q[++tt].l=read(),q[tt].r=read();q[tt].pl=(q[tt].l-1)/T+1;q[tt].id=i;len[i]+=q[tt].r-q[tt].l+1; } std::sort(q+1,q+tt+1); register int l=1,r=0;now.reset(); memset(num,0,sizeof num); for(i=1;i<=tt;++i) { for(;r<q[i].r;++r) num[a[r+1]]++,now[a[r+1]+num[a[r+1]]-1]=1; for(;l>q[i].l;--l) num[a[l-1]]++,now[a[l-1]+num[a[l-1]]-1]=1; for(;r>q[i].r;--r) now[a[r]+num[a[r]]-1]=0,--num[a[r]]; for(;l<q[i].l;++l) now[a[l]+num[a[l]]-1]=0,--num[a[l]]; quer[q[i].id]&=now; } for(i=1;i<=R-L+1;++i) printf("%d\n",len[i]-3*quer[i].count()); } int main() { n=read();m=read(); register int i;T=ceil(sqrt((double)n)); for(i=1;i<=n;++i) nums[i]=a[i]=read(); std::sort(nums+1,nums+n+1); for(i=1;i<=n;++i) a[i]=std::lower_bound(nums+1,nums+n+1,a[i])-nums; int N1=m/3+1,N2=2*N1; solve(1,min(N1,m));solve(min(N1,m)+1,min(N2,m));solve(min(N2,m)+1,m); return 0; }
Blog來自PaperCloud,未經允許,請勿轉載,TKS!