• 数据结构(树套树):ZJOI 2013 K大数查询


      

      有几个点卡常数……

      发现若第一维为位置,第二维为大小,那么修改时第一维修改区间,查询时第一维查询区间,必须挂标记。而这种情况下标记很抽象,而且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 }
  • 相关阅读:
    215. Kth Largest Element in an Array (have better solution )
    414. Third Maximum Number
    442. Find All Duplicates in an Array
    448. Find All Numbers Disappeared in an Array
    485. Max Consecutive Ones
    532. K-diff Pairs in an Array
    8. String to Integer (atoi)
    7. Reverse Integer
    [CTSC2012]熟悉的文章(广义后缀自动机+二分答案+单调队列优化DP)
    BZOJ 2119 股市的预测(后缀数组)
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5616464.html
Copyright © 2020-2023  润新知