zoukankan      html  css  js  c++  java
  • bzoj 3110

     
    整体二分。
    首先,第k大问题是满足二分性的(只要我们能够快速求出集合中比某个数小的数的个数,那么就可以快速找出该集合的第K大)。
    然后考虑整体二分,关键是我们怎么将询问分到其对应的答案子区间中。
    和普通的区间第K大的做法一样,我们先将修改按照大小排序(普通的区间第K大就是给出的原序列,而这里就是区间修改)。
    设对于答案区间[lf,rg],有询问集合q,求出当前区间的mid,然后二分外面的修改数组,找出大小在[lf,mid]中的所有修改,将它们提出来,按照修改的顺序排序,然后和询问一起沿时间轴扫过去,过程中维护一个线段树,其以位置为下表,表示从最开始到现在每个位置中的数比mid小的数的个数。遇到修改就将对应的区间每个位置+1(区间修改),遇到询问就查询其对应区间的和(区间求和),根据其区间中小于等于mid的数的个数判断答案是与mid的关系,从而确定它的答案子区间。
     
    时间复杂度:O( m * logn * logn )(改天把树套树的做法补上)。
     
      1 /**************************************************************
      2     Problem: 3110
      3     User: idy002
      4     Language: C++
      5     Result: Accepted
      6     Time:5584 ms
      7     Memory:6432 kb
      8 ****************************************************************/
      9  
     10 #include <cstdio>
     11 #include <vector>
     12 #include <algorithm>
     13 #define N 50010
     14 using namespace std;
     15  
     16 struct Query {
     17     int id, l, r, k;
     18     int ans;
     19     Query(){}
     20     Query( int id, int l, int r, int k ):id(id),l(l),r(r),k(k){}
     21 };
     22 struct Modify {
     23     int id, l, r, k;
     24     Modify(){}
     25     Modify( int id, int l, int r, int k ):id(id),l(l),r(r),k(k){}
     26     bool operator<( const Modify &o ) const {
     27         return k<o.k;
     28     }
     29 };
     30 bool operator<( const Modify &o, int k ) { return o.k<k; }
     31 bool operator<( int k, const Modify &o ) { return k<o.k; }
     32 struct Node {
     33     int s, tag;
     34     Node *ls, *rs;
     35 }pool[3*N], *tail=pool, *root;
     36  
     37 int n, m, maxk;
     38 int disc[N], dtot;
     39 int ans[N];
     40 Query qry[N]; int tq;
     41 Modify mdf[N]; int tm;
     42  
     43 inline void update( Node *nd ) {
     44     nd->s = nd->ls->s + nd->rs->s;
     45 }
     46 Node *build( int lf, int rg ) {
     47     Node *nd = ++tail;
     48     if( lf==rg ) return nd;
     49     int mid=(lf+rg)>>1;
     50     nd->ls = build( lf, mid );
     51     nd->rs = build( mid+1, rg );
     52     return nd;
     53 }
     54 void pushdown( Node *nd, int lf, int rg ) {
     55     if( nd->tag ) {
     56         int mid=(lf+rg)>>1;
     57         nd->ls->s += (mid-lf+1)*nd->tag;
     58         nd->rs->s += (rg-mid)*nd->tag;
     59         nd->ls->tag += nd->tag;
     60         nd->rs->tag += nd->tag;
     61         nd->tag = 0;
     62     }
     63 }
     64 void modify( Node *nd, int lf, int rg, int L, int R, int delta ) {
     65     if( L<=lf && rg<=R ) {
     66         nd->s += (rg-lf+1)*delta;
     67         nd->tag += delta;
     68         return;
     69     }
     70     pushdown(nd,lf,rg);
     71     int mid=(lf+rg)>>1;
     72     if( L<=mid ) modify( nd->ls, lf, mid, L, R, delta );
     73     if( R>mid ) modify( nd->rs, mid+1, rg, L, R, delta );
     74     update( nd );
     75 }
     76 int query( Node *nd, int lf, int rg, int L, int R ) {
     77     if( L<=lf && rg<=R ) return nd->s;
     78     pushdown(nd,lf,rg);
     79     int mid=(lf+rg)>>1;
     80     int rt = 0;
     81     if( L<=mid ) rt+=query( nd->ls, lf, mid, L, R );
     82     if( R>mid ) rt+=query( nd->rs, mid+1, rg, L, R );
     83     update(nd);
     84     return rt;
     85 }
     86 bool cmp_id( int a, int b ) {
     87     return mdf[a].id<mdf[b].id;
     88 }
     89 void binary( int lf, int rg, vector<int> vq ) {
     90     if( vq.empty() ) return;
     91     if( lf==rg ) {
     92         for( int t=0; t<vq.size(); t++ ) 
     93             qry[vq[t]].ans = -disc[lf];
     94         return;
     95     }
     96     int mid=(lf+rg)>>1;
     97     int lpos = lower_bound( mdf+1, mdf+1+tm, lf ) - mdf;
     98     int rpos = upper_bound( mdf+1, mdf+1+tm, mid ) - mdf - 1;
     99     vector<int> vm;
    100     for( int i=lpos; i<=rpos; i++ )
    101         vm.push_back(i);
    102     sort( vm.begin(), vm.end(), cmp_id );
    103  
    104     int i, j;
    105     vector<int> ql, qr;
    106     for( i=0,j=-1; i<vq.size(); i++ ) {
    107         while( j+1<vm.size() && mdf[vm[j+1]].id<qry[vq[i]].id ) {
    108             j++;
    109             modify( root, 1, n, mdf[vm[j]].l, mdf[vm[j]].r, +1 );
    110 //          fprintf( stderr, "modify( %d %d %d )
    ", mdf[vm[j]].l, mdf[vm[j]].r,
    111 //                  +1 );
    112         }
    113         int c = query( root, 1, n, qry[vq[i]].l, qry[vq[i]].r );
    114 //      fprintf( stderr, "query( %d %d ) = %d
    ", qry[vq[i]].l, qry[vq[i]].r, c );
    115         if( qry[vq[i]].k<=c )
    116             ql.push_back( vq[i] );
    117         else {
    118             qr.push_back( vq[i] );
    119             qry[vq[i]].k -= c;
    120         }
    121     }
    122     for( int k=0; k<=j; k++ ) {
    123         modify( root, 1, n, mdf[vm[k]].l, mdf[vm[k]].r, -1 );
    124 //      fprintf( stderr, "modify( %d %d %d )
    ", mdf[vm[k]].l, mdf[vm[k]].r, -1 );
    125     }
    126     binary( lf, mid, ql );
    127     binary( mid+1, rg, qr );
    128 }
    129 int main() {
    130     scanf( "%d%d", &n, &m );
    131     for( int i=1,o,l,r,k; i<=m; i++ ) {
    132         scanf( "%d%d%d%d", &o, &l, &r, &k );
    133         if( o==2 ) {
    134             qry[++tq] = Query(i,l,r,k);
    135             maxk = max( maxk, k );
    136         } else {
    137             k = -k;
    138             mdf[++tm] = Modify(i,l,r,k);
    139             disc[++dtot] = k;
    140         }
    141     }
    142     sort( disc+1, disc+1+dtot );
    143     dtot = unique( disc+1, disc+1+dtot ) - disc - 1;
    144  
    145     sort( mdf+1, mdf+1+tm );
    146     for( int i=1; i<=tm; i++ )
    147         mdf[i].k = lower_bound( disc+1, disc+1+dtot, mdf[i].k ) - disc;
    148  
    149     vector<int> vq;
    150     for( int i=1; i<=tq; i++ ) 
    151         vq.push_back(i);
    152      
    153     root = build( 1, n );
    154     binary( 1, dtot, vq );
    155     for( int i=1; i<=tq; i++ )
    156         printf( "%d
    ", qry[i].ans );
    157 }
    View Code

    树状数组套线段树。
    可以直接在树状数组上二分,可以少一个log的复杂度。
    收获:
      1、对树状数组的结构更清晰了,树状数组中的一个节点u,可以有四种操作:
        1)跳到左边第一个不是其子树的节点:u-=lowbit(u)
        2)跳到它的父亲节点:u+=lowbit(u)
        3)跳到它的最左边的儿子:u-=lowbit(u)/2
        4)跳到它右边大小是它一半的第一个节点:u+=lowbit(u)/2
      我们常用的是前两种,而这道题如果用上后两种操作,就可以在树状数组上二分。(其实我们可以把树状数组看成是一棵二叉树,对于一个节点u,它的左儿子是3操作到达的   点,它的右儿子是4操作到达的点,奇数点是叶子)
      2、“位置线段树?”
     
      1 /**************************************************************
      2     Problem: 3110
      3     User: idy002
      4     Language: C++
      5     Result: Accepted
      6     Time:13392 ms
      7     Memory:490776 kb
      8 ****************************************************************/
      9  
     10 #include <cstdio>
     11 #include <algorithm>
     12 #define N 50010
     13 #define S 25000010
     14 using namespace std;
     15  
     16 typedef long long dnt;
     17  
     18 struct Node {
     19     dnt s;
     20     int tag;
     21     Node *ls, *rs;
     22 }pool[S], *tail=pool, *null;
     23 struct Proc {
     24     int o, l, r; 
     25     dnt k;
     26     Proc(){}
     27     Proc( int o, int l, int r, dnt k ):o(o),l(l),r(r),k(k){}
     28 };
     29  
     30 int n, m;
     31 int disc[N], dtot;
     32 Node *bit[65537]; int mbit=65536;
     33 Node *cbit[65537];
     34 Proc prc[N];
     35  
     36 Node *newnode() {
     37     Node *nd = ++tail;
     38     nd->ls = nd->rs = null;
     39     return nd;
     40 }
     41 void pushdown( Node *nd, int lf, int rg ) {
     42     if( nd->tag ) {
     43         if( nd->ls==null ) nd->ls = newnode();
     44         if( nd->rs==null ) nd->rs = newnode();
     45         int mid=(lf+rg)>>1;
     46         nd->ls->tag += nd->tag;
     47         nd->rs->tag += nd->tag;
     48         nd->ls->s += (dnt) (mid-lf+1)*nd->tag;
     49         nd->rs->s += (dnt) (rg-mid)*nd->tag;
     50         nd->tag = 0;
     51     }
     52 }
     53 void update( Node *nd ) {
     54     nd->s = nd->ls->s + nd->rs->s;
     55 }
     56 void modify( Node *nd, int lf, int rg, int L, int R, int delta ) {
     57     if( L<=lf && rg<=R ) {
     58         nd->s += (dnt) (rg-lf+1)*delta;
     59         nd->tag += delta;
     60         return;
     61     }
     62     int mid=(lf+rg)>>1;
     63     pushdown(nd,lf,rg);
     64     if( L<=mid ) {
     65         if( nd->ls==null ) nd->ls = newnode();
     66         modify( nd->ls, lf, mid, L, R, delta );
     67     }
     68     if( R>mid ) {
     69         if( nd->rs==null ) nd->rs = newnode();
     70         modify( nd->rs, mid+1, rg, L, R, delta );
     71     }
     72     update( nd );
     73 }
     74 dnt query( Node *nd, int lf, int rg, int L, int R ) {
     75     if( nd==null ) return 0;
     76     if( L<=lf && rg<=R ) return nd->s;
     77     int mid=(lf+rg)>>1;
     78     pushdown(nd,lf,rg);
     79     dnt rt = 0;
     80     if( L<=mid ) rt += query( nd->ls, lf, mid, L, R );
     81     if( R>mid ) rt += query( nd->rs, mid+1, rg, L, R );
     82     update( nd );
     83     return rt;
     84 }
     85 void init() {
     86     null = ++tail;
     87     null->s = null->tag = 0;
     88     for( int i=1; i<=mbit; i++ ) {
     89         bit[i] = newnode();
     90         cbit[i] = newnode();
     91     }
     92 }
     93 void modify( int l, int r, int k ) {
     94     for( int i=k; i<=mbit; i+=i&-i ) {
     95 //      if( i<=3 ) fprintf( stderr, "modify( %d %d %d +1 )
    ", i, l, r );
     96         modify( bit[i], 1, n, l, r, +1 );
     97     }
     98     modify( cbit[k], 1, n, l, r, +1 );
     99 }
    100 int query( int l, int r, dnt rk ) {
    101     int u = mbit;
    102     while((u&1)==0) {
    103         int d = (u&-u)>>1;
    104         dnt cc = query( bit[u], 1, n, l, r );
    105         dnt lc = cc-query( cbit[u], 1, n, l, r );
    106 //      fprintf( stderr, "%d ls=%lld cc=%lld rk=%lld
    ", u, lc, cc, rk );
    107         if( rk<=lc ) {
    108             u -= d;
    109         } else if( rk<=cc ) {
    110             return u;
    111         } else {
    112             u += d;
    113             rk -= cc;
    114         }
    115     }
    116     return u;
    117 }
    118 int main() {
    119     scanf( "%d%d", &n, &m );
    120     for( int i=1; i<=m; i++ ) {
    121         int o, l, r;
    122         dnt k;
    123         scanf( "%d%d%d%lld", &o, &l, &r, &k );
    124         if( o==1 ) {
    125             k = -k;
    126             disc[++dtot] = k;
    127             prc[i] = Proc( o, l, r, k );
    128         } else {
    129             prc[i] = Proc( o, l, r, k );
    130         }
    131     }
    132     sort( disc+1, disc+1+dtot );
    133     dtot = unique( disc+1, disc+1+dtot ) - disc - 1;
    134     init();
    135     for( int i=1; i<=m; i++ )
    136         if( prc[i].o==1 )
    137             prc[i].k=lower_bound(disc+1,disc+1+dtot,prc[i].k)-disc;
    138     for( int i=1; i<=m; i++ ) {
    139         if( prc[i].o==1 ) 
    140             modify( prc[i].l, prc[i].r, prc[i].k );
    141         else
    142             printf( "%d
    ", -disc[query(prc[i].l,prc[i].r,prc[i].k)] );
    143     }
    144 }
    145  
    146 
    View Code
  • 相关阅读:
    搜索算法总结
    浅谈cocosd之autorelease etain elease的理解
    lua和C++的交互(1)
    Unity相对于Cocos2d-x的比较
    Lua弱表Weak table
    socket编程学习step2
    ppt述职摘要
    LuaJavaBridge
    鱼书学习小结(一)
    网络协议HTTP TCP/UDP 浏览器缓存 Restful(十)
  • 原文地址:https://www.cnblogs.com/idy002/p/4464096.html
Copyright © 2011-2022 走看看