#2461. 「2018 集训队互测 Day 1」完美的队列
传送门:
题解:
直接做可能一次操作加入队列同时会弹出很多数字,无法维护;一个操作的有效区间是连续的,考虑找到操作x结束的时间ed[x],即执行(x,ed[x]]可以将x加入的数全部弹出,这样用一个vis记录数字次数就可以维护个数;
一种比较暴力的做法是:枚举x,用一个线段树维护还可以放多少个元素,枚举ed[x]更新,但是这样不满足单调性无法two-pointers;
考虑分块。ed[x]即对x的每一个块的ed取max
考虑整块。枚举每一个整块,用一个b维护还可以放的元素初始化为ai,cov维护整块被完整覆盖了多少次,枚举x,再枚举ed[x],当mx(bi)-cov==0时表示x的当前块在这里结束,更新ed[x],此时是有单调性的可以two-pointers,复杂度$O(m sqrt{n})$;
考虑散块。在处理完整块的时候枚举整块里的元素处理散块,如果直接像整块那样枚举m个操作,复杂度是$O(nm)$的,但如果在处理整块时用一个d数组记录下每一个和当前整块相交但不覆盖的操作,这样就是$O(m sqrt{n})$的,因为一个操作最多有$sqrt{n}$个散块,同样枚举d的元素做two-pointers,注意这是一个散块的ed不一定只出现在d里,可能出现在d[i]和d[i-1]中间某个将整块完整覆盖的操作,所以还需要记录完全覆盖整块的操作的前缀和s[], 覆盖整块的编号c[] , d[i]前面的第一个覆盖整块的操作e[i]。
细节多;
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 #include<cmath> 7 #include<vector> 8 #include<stack> 9 #include<map> 10 #define Run(i,l,r) for(int i=l;i<=r;i++) 11 #define Don(i,l,r) for(int i=l;i>=r;i--) 12 #define ll long long 13 #define inf 0x3f3f3f3f 14 using namespace std; 15 const int N=100010; 16 int n,m,a[N],b[N],c[N],d[N],e[N],vis[N],num,cn,dn,l[N],r[N],v[N],ed[N],s[N]; 17 inline void upd(int&x,int y){if(x<y)x=y;} 18 struct node{int x,y;}; 19 vector<node>g[N]; 20 char gc(){ 21 static char*p1,*p2,S[1000000]; 22 if(p1==p2)p2=(p1=S)+fread(S,1,1000000,stdin); 23 return(p1==p2)?EOF:*p1++; 24 }// 25 int rd(){ 26 int x=0; char C=gc(); 27 while(C<'0'||C>'9')C=gc(); 28 while(C>='0'&&C<='9')x=(x<<1)+(x<<3)+C-'0',C=gc(); 29 return x; 30 }// 31 int main(){ 32 //freopen("loj2461.in","r",stdin); 33 //freopen("loj2461.out","w",stdout); 34 n=rd(); m=rd(); 35 Run(i,1,n)a[i]=rd(); 36 Run(i,1,m)l[i]=rd(),r[i]=rd(),v[i]=rd(); 37 int B = sqrt(n); 38 for(int L=1;L<=n;L+=B){ 39 cn=dn=0; 40 int R=min(n,L+B-1),mx=0,cov=0; 41 Run(i,L,R)upd(mx,b[i]=a[i]); 42 for(int i=1,j=0;i<=m;i++){ 43 if(l[i]<=L&&r[i]>=R)cov--; 44 else if(l[i]<=R&&r[i]>=L){ 45 Run(k,max(l[i],L),min(r[i],R))b[k]++; 46 mx=0;Run(k,L,R)upd(mx,b[k]); 47 } 48 while(j<=m&&mx-cov>0){ 49 j++; 50 if(l[j]<=L&&r[j]>=R)cov++; 51 else if(l[j]<=R&&r[j]>=L){ 52 Run(k,max(l[j],L),min(r[j],R))b[k]--; 53 mx=0;Run(k,L,R)upd(mx,b[k]); 54 } 55 } 56 s[i]=s[i-1]; 57 if(l[i]<=L&&r[i]>=R)upd(ed[i],j),s[c[++cn]=i]++; 58 else if(l[i]<=R&&r[i]>=L)d[++dn]=i,e[dn]=cn; 59 }// 60 for(int i=L;i<=R;i++){ 61 mx=a[i]; 62 for(int j=1,k=0;j<=dn;j++){ 63 mx+=s[d[j]]-s[d[j-1]]; 64 if(l[d[j]]<=i&&r[d[j]]>=i){ 65 mx++; 66 while(k<dn&&mx>0)k++,mx-=s[d[k]]-s[d[k-1]]+(l[d[k]]<=i&&r[d[k]]>=i); 67 if(mx>0){ 68 if(s[m]-s[d[k]]<mx)upd(ed[d[j]],m+1); 69 else upd(ed[d[j]],c[e[k]+mx]); 70 continue; 71 } 72 if(l[d[k]]<=i&&r[d[k]]>=i)upd(ed[d[j]],mx<0?c[e[k]+mx+1]:d[k]); 73 else upd(ed[d[j]],c[e[k]+mx]); 74 } 75 } 76 }// 77 }// 78 Run(i,1,m)g[i].push_back((node){v[i],1}),g[ed[i]].push_back((node){v[i],-1}); 79 for(int i=1;i<=m;i++){ 80 for(int j=0;j<(int)g[i].size();j++){ 81 int x=g[i][j].x,y=g[i][j].y; 82 if((vis[x]+y==0)^(vis[x]==0))num+=y; 83 vis[x]+=y; 84 } 85 printf("%d ",num); 86 } 87 return 0; 88 }//by tkys_Austin;