有几个点卡常数……
发现若第一维为位置,第二维为大小,那么修改时第一维修改区间,查询时第一维查询区间,必须挂标记。而这种情况下标记很抽象,而且Push_down不是O(1)的,并不可行。
那要怎么做呢?不妨交换一下,第一维为大小,第二维为位置,在第二维中挂标记,这样Push_down就是O(1)的了。
做完这道题,我最大的启发就是:树套树不适于在第一维挂标记,因为标记的维度会是一维的,根本不好维护。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <ctime> 5 using namespace std; 6 const int maxn=50010; 7 const int maxm=20000010; 8 int rt[maxn*4],tot,n,m; 9 int ch[maxm][2],sum[maxm],tag[maxm]; 10 11 void Push_up(int x){ 12 sum[x]=sum[ch[x][0]]+sum[ch[x][1]]; 13 } 14 15 void Add(int &x,int l,int r,int d){ 16 if(!x)x=++tot; 17 sum[x]+=(r-l+1)*d; 18 tag[x]+=d; 19 } 20 21 void Push_down(int x,int l,int r){ 22 if(tag[x]&&l!=r){ 23 int mid=(l+r)>>1; 24 if(!ch[x][0])ch[x][0]=++tot; 25 if(!ch[x][1])ch[x][1]=++tot; 26 sum[ch[x][0]]+=(mid-l+1)*tag[x];tag[ch[x][0]]+=tag[x]; 27 sum[ch[x][1]]+=(r-mid)*tag[x];tag[ch[x][1]]+=tag[x]; 28 tag[x]=0; 29 } 30 } 31 32 void Update(int &x,int l,int r,int a,int b){ 33 if(!x)x=++tot; 34 Push_down(x,l,r); 35 if(l>=a&&r<=b){sum[x]+=r-l+1;tag[x]+=1;return;} 36 int mid=(l+r)>>1; 37 if(mid>=a)Update(ch[x][0],l,mid,a,b); 38 if(mid<b)Update(ch[x][1],mid+1,r,a,b); 39 Push_up(x); 40 } 41 42 void Modify(int x,int l,int r,int g,int a,int b){ 43 Update(rt[x],1,n,a,b); 44 if(l==r)return; 45 int mid=(l+r)>>1; 46 if(mid>=g)Modify(x<<1,l,mid,g,a,b); 47 else Modify(x<<1|1,mid+1,r,g,a,b); 48 } 49 50 int Query(int x,int l,int r,int a,int b){ 51 if(!x)return 0; 52 Push_down(x,l,r); 53 if(l>=a&&r<=b)return sum[x]; 54 int mid=(l+r)>>1,ret=0; 55 if(mid>=a)ret=Query(ch[x][0],l,mid,a,b); 56 if(mid<b)ret+=Query(ch[x][1],mid+1,r,a,b); 57 return ret; 58 } 59 60 int Solve(int l,int r,int k){ 61 int lo=1,hi=n,p=1; 62 while(lo<hi){ 63 int mid=(lo+hi)>>1,tmp; 64 tmp=Query(rt[p<<1],1,n,l,r); 65 if(tmp>=k)hi=mid,p<<=1; 66 else lo=mid+1,p=p<<1|1,k-=tmp; 67 } 68 return hi; 69 } 70 71 int op,a,b,c; 72 int main(){ 73 #ifndef ONLINE_JUDGE 74 freopen("zjoi13_sequence.in","r",stdin); 75 freopen("zjoi13_sequence.out","w",stdout); 76 #endif 77 scanf("%d%d",&n,&m); 78 while(m--){ 79 scanf("%d%d%d%d",&op,&a,&b,&c); 80 if(op==1)Modify(1,1,n,n-c+1,a,b); 81 else printf("%d ",n-Solve(a,b,c)+1); 82 } 83 //printf("%.2f ",(double)clock()/CLOCKS_PER_SEC); 84 return 0; 85 }
然后就是喜闻乐见的整体二分,很好理解。
有些地方没有缩行,打丑了,理论上60行足矣,这就是整体二分的威力!
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=50010; 6 struct Node{ 7 int tp,l,r,k,id,tmp; 8 }p[maxn],tmp[maxn]; 9 10 int b0[maxn],b1[maxn]; 11 int v0[maxn],v1[maxn]; 12 int ans[maxn],n,Q,tim,cntQ; 13 14 void Add0(int x,int d){ 15 while(x<=n){ 16 b0[x]=v0[x]==tim?b0[x]+d:d; 17 v0[x]=tim; 18 x+=x&(-x); 19 } 20 } 21 22 void Add1(int x,int d){ 23 while(x<=n){ 24 b1[x]=v1[x]==tim?b1[x]+d:d; 25 v1[x]=tim; 26 x+=x&(-x); 27 } 28 } 29 30 void Update(int l,int r,int d){ 31 Add0(l,d); 32 Add0(r+1,-d); 33 Add1(l,-(l-1)*d); 34 Add1(r+1,r*d); 35 } 36 37 int Query(int x){ 38 int ret=0; 39 for(int i=x;i;i-=i&(-i)) 40 ret+=v0[i]==tim?b0[i]:0; 41 ret*=x; 42 for(int i=x;i;i-=i&(-i)) 43 ret+=v1[i]==tim?b1[i]:0; 44 return ret; 45 } 46 47 int Que(int l,int r){ 48 return Query(r)-Query(l-1); 49 } 50 51 void Solve(int h,int t,int l,int r){ 52 if(h>t)return; 53 if(l==r){ 54 for(int i=h;i<=t;i++) 55 ans[p[i].id]=l; 56 return; 57 } 58 int mid=(l+r)>>1; 59 int ct1=h,ct2=h;++tim; 60 for(int i=h;i<=t;i++){ 61 if(p[i].tp==1){ 62 if(p[i].k>mid)continue; 63 Update(p[i].l,p[i].r,1); 64 ct2+=1; 65 } 66 else{ 67 p[i].tmp=Que(p[i].l,p[i].r); 68 if(p[i].tmp>=p[i].k)ct2+=1; 69 } 70 } 71 for(int i=h;i<=t;i++){ 72 if(p[i].tp==1){ 73 if(p[i].k>mid)tmp[ct2++]=p[i]; 74 else tmp[ct1++]=p[i]; 75 } 76 else{ 77 if(p[i].tmp>=p[i].k)tmp[ct1++]=p[i]; 78 else p[i].k-=p[i].tmp,tmp[ct2++]=p[i]; 79 } 80 } 81 for(int i=h;i<=t;i++)p[i]=tmp[i]; 82 Solve(h,ct1-1,l,mid);Solve(ct1,t,mid+1,r); 83 } 84 85 int main(){ 86 #ifndef ONLINE_JUDGE 87 freopen("zjoi13_sequence.in","r",stdin); 88 freopen("zjoi13_sequence.out","w",stdout); 89 #endif 90 scanf("%d%d",&n,&Q); 91 for(int i=1;i<=Q;i++){ 92 scanf("%d%d",&p[i].tp,&p[i].l); 93 scanf("%d%d",&p[i].r,&p[i].k); 94 if(p[i].tp==2){ 95 p[i].id=++cntQ; 96 p[i].k=Que(p[i].l,p[i].r)-p[i].k+1; 97 } 98 else 99 Update(p[i].l,p[i].r,1); 100 } 101 102 Solve(1,Q,1,n); 103 104 for(int i=1;i<=cntQ;i++) 105 printf("%d ",ans[i]); 106 return 0; 107 }