在在线算法的角度思考,发现序列排序的复杂度如何也难以简化(否则想出来的简化办法就进教科书了),故尝试从离线算法的角度思考。
尝试思考二分。二分在大部分情况下都能将模型大程度简化(或说二分多提供了一个限制性条件,将各种奇怪的问题简化为判定性问题,毕竟“能不能”和“怎么才能”这两种问题的难度大部分情况下是完全不同的吧),对于二分的答案mid,按与mid的大于等于/小于的关系将序列转化为01数列,发现给一段01序列排序只需log n的时间复杂度。故有做法:
注意一段区间的1的个数cnt可能为0,这时对于线段树的修改操作的区间会发生区间左端点大于右端点的诡异情形,故需特判,否则RE。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 5 #define dmid ((l+r)>>1) 6 7 using namespace std; 8 9 const int N=1e5+5; 10 11 int n,m,a[N],ans,Mid,tre[N<<2],mod[N][3],q; 12 13 bool lzy[N<<2],sig[N<<2]; 14 15 inline int read() 16 { 17 int x=0; 18 char ch=getchar(); 19 while(!isdigit(ch)) 20 ch=getchar(); 21 while(isdigit(ch)) 22 x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); 23 return x; 24 } 25 26 void build(int t,int l,int r) 27 { 28 if(l==r) 29 { 30 tre[t]=(a[l]>=Mid); 31 return; 32 } 33 int mid=(l+r)>>1; 34 build(t<<1,l,mid); 35 build((t<<1)+1,mid+1,r); 36 tre[t]=tre[t<<1]+tre[(t<<1)+1]; 37 } 38 39 inline void down(int t,int l,int r) 40 { 41 if(!lzy[t]) 42 return; 43 int mid=(l+r)>>1; 44 lzy[t<<1]=lzy[(t<<1)+1]=1; 45 sig[t<<1]=sig[(t<<1)+1]=sig[t]; 46 tre[t<<1]=(mid-l+1)*sig[t]; 47 tre[(t<<1)+1]=(r-mid)*sig[t]; 48 lzy[t]=0; 49 } 50 51 int query(int t,int l,int r,int ll,int rr) 52 { 53 if(ll<=l&&r<=rr) 54 return tre[t]; 55 down(t,l,r); 56 int mid=(l+r)>>1; 57 if(ll<=mid) 58 { 59 if(rr>mid) 60 return query(t<<1,l,mid,ll,rr)+query((t<<1)+1,mid+1,r,ll,rr); 61 else 62 return query(t<<1,l,mid,ll,rr); 63 } 64 else 65 return query((t<<1)+1,mid+1,r,ll,rr); 66 } 67 68 void modify(int t,int l,int r,int ll,int rr,int x) 69 { 70 if(ll<=l&&r<=rr) 71 { 72 lzy[t]=1; 73 sig[t]=x; 74 tre[t]=(r-l+1)*x; 75 return; 76 } 77 down(t,l,r); 78 if(ll<=dmid) 79 modify(t<<1,l,dmid,ll,rr,x); 80 if(rr>dmid) 81 modify((t<<1)+1,dmid+1,r,ll,rr,x); 82 tre[t]=tre[t<<1]+tre[(t<<1)+1]; 83 } 84 85 inline int check() 86 { 87 build(1,1,n); 88 memset(lzy,0,sizeof lzy); 89 int cnt,ll,rr; 90 for(int i=1;i<=m;++i) 91 { 92 ll=mod[i][1],rr=mod[i][2]; 93 cnt=query(1,1,n,ll,rr); 94 if(mod[i][0]) 95 { 96 if(cnt) 97 modify(1,1,n,ll,ll+cnt-1,1); 98 modify(1,1,n,ll+cnt,rr,0); 99 } 100 else 101 { 102 modify(1,1,n,ll,rr-cnt,0); 103 if(cnt) 104 modify(1,1,n,rr-cnt+1,rr,1); 105 } 106 } 107 return query(1,1,n,q,q); 108 } 109 110 int main() 111 { 112 n=read();m=read(); 113 for(int i=1;i<=n;++i) 114 a[i]=read(); 115 for(int i=1;i<=m;++i) 116 mod[i][0]=read(),mod[i][1]=read(),mod[i][2]=read(); 117 q=read(); 118 int l=1,r=n; 119 while(l<=r) 120 { 121 Mid=(l+r)>>1; 122 if(check()) 123 { 124 ans=Mid; 125 l=Mid+1; 126 } 127 else 128 r=Mid-1; 129 } 130 cout<<ans; 131 return 0; 132 }
参考资料: