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
原文地址:https://www.cnblogs.com/idy002/p/4464096.html