日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

4939: [Ynoi2016]掉进兔子洞 莫队 压位

發(fā)布時間:2023/12/20 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 4939: [Ynoi2016]掉进兔子洞 莫队 压位 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題面:http://www.lydsy.com/JudgeOnline/problem.php?id=4939


大意:
每個詢問有三個區(qū)間。將三個區(qū)間里都出現(xiàn)的數(shù)字一個一個地刪除,直到不能操作為止,求這時三個區(qū)間里總共還剩下多少個數(shù)字。

稍微思考一下發(fā)現(xiàn)就是求3i=1(ri?li+1)?3109i=0min{cnt1i,cnt2i,cnt3i}∑i=13(ri?li+1)?3∑i=0109min{cnt1i,cnt2i,cnt3i},其中cntijcntij為第i個區(qū)間里數(shù)字j的出現(xiàn)次數(shù)。

顯然要先離散化。考慮離散化之后如何處理。發(fā)現(xiàn)用什么數(shù)據(jù)結(jié)構(gòu)都不好處理,而這又是一個關(guān)于區(qū)間的問題,所以考慮把每個詢問拆成三個區(qū)間,使用莫隊(duì)算法。然而發(fā)現(xiàn)雖然我們很容易通過莫隊(duì)維護(hù)cntijcntij,但是后面的求和卻不好維護(hù)。這里正解是壓位。

由于bitset每一位上的值只有0/1兩種,不能直接維護(hù)cntijcntij,考慮更特殊的情況。如果aiai的值兩兩不同,那么cntijcntij就只有0/1兩種取值,這時候就能夠用bitset維護(hù)每個數(shù)字在區(qū)間內(nèi)是否出現(xiàn)過,109i=0min{cnt1i,cnt2i,cnt3i}∑i=0109min{cnt1i,cnt2i,cnt3i}就是三個區(qū)間的bitset取交后1的位置個數(shù)。

考慮處理aiai不必兩兩相同的情況。拿樣例來說:

5 2
1 2 2 3 3
1 2 2 3 3 4
1 5 1 5 1 5

1 2 2 3 3離散化之后是1 2 2 4 4。那么離散化之后,將bitset里第一位表示1是否出現(xiàn)過,第二位表示第一個2是否出現(xiàn)過,第三位表示第二個2是否出現(xiàn)過,第四位表示第一個4是否出現(xiàn)過,第五位表示第二個4是否出現(xiàn)過。這樣處理之后,發(fā)現(xiàn)就能夠以相同的方式計(jì)算109i=0min{cnt1i,cnt2i,cnt3i}∑i=0109min{cnt1i,cnt2i,cnt3i}了。

注意到直接對所有詢問用莫隊(duì)處理會MLE,那么把詢問可以分成幾塊分別處理,以重復(fù)利用空間。


代碼:

#include<stdio.h> #include<algorithm> #include<cstring> #include<bitset> #include<cmath> #define MAXN 100005 using namespace std;int N,M,Be[MAXN],A[MAXN],Hash[MAXN],Ans[MAXN];struct seg{int l,r,id; }Q[MAXN*3];struct node{int l1,r1,l2,r2,l3,r3; }data[MAXN];bool operator<(seg a,seg b){if(Be[a.l]==Be[b.l])return a.r<b.r;return Be[a.l]<Be[b.l]; }bitset<MAXN>Tmp,f[25005]; int Cnt[MAXN]; bool vis[25005];void Update(int p,int k){p=A[p];Cnt[p]+=k;if(k==1)Tmp[p+Cnt[p]-2]=1;else Tmp[p+Cnt[p]-1]=0; }void Solve(int l,int r){int i,tot=0;for(i=l;i<=r;i++){Q[++tot]=(seg){data[i].l1,data[i].r1,i};Q[++tot]=(seg){data[i].l2,data[i].r2,i};Q[++tot]=(seg){data[i].l3,data[i].r3,i};}sort(Q+1,Q+tot+1);int L=1,R=0;Tmp.reset();memset(vis,0,sizeof(vis));memset(Cnt,0,sizeof(Cnt));for(i=1;i<=tot;i++){while(R<Q[i].r)Update(++R,1);while(R>Q[i].r)Update(R--,-1);while(L<Q[i].l)Update(L++,-1);while(L>Q[i].l)Update(--L,1);if(vis[Q[i].id-l])f[Q[i].id-l]&=Tmp;else f[Q[i].id-l]=Tmp,vis[Q[i].id-l]=1;}for(i=l;i<=r;i++)Ans[i]-=f[i-l].count()*3; }int main(){int i,j;scanf("%d%d",&N,&M);for(i=1;i<=N;i++){scanf("%d",&A[i]);Hash[i]=A[i];}sort(Hash+1,Hash+N+1);for(i=1;i<=N;i++)A[i]=lower_bound(Hash+1,Hash+N+1,A[i])-Hash;int S=sqrt(N);for(i=j=1;i<=N;i++){Be[i]=j;if(i%S==0)j++;}for(i=1;i<=M;i++){int l1,r1,l2,r2,l3,r3;scanf("%d%d%d%d%d%d",&l1,&r1,&l2,&r2,&l3,&r3);Ans[i]+=r1-l1+r2-l2+r3-l3+3;data[i]=(node){l1,r1,l2,r2,l3,r3};}Solve(1,min(25000,M));if(M>25000)Solve(25001,min(50000,M));if(M>50000)Solve(50001,min(75000,M));if(M>75000)Solve(75001,M);//對詢問分塊處理for(i=1;i<=M;i++)printf("%d\n",Ans[i]); }

總結(jié)

以上是生活随笔為你收集整理的4939: [Ynoi2016]掉进兔子洞 莫队 压位的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。