[BZOJ3110][Zjoi2013]-K大数查询-树套树
2017-11-22 15:46
260 查看
说在前面
第一次写树套树,从上午9点写到下午三点半,先是自己没想清楚,yy了个时间复杂度起飞的套法。然后换了一种套法继续写,然而又被人造数据强行卡int= =#题目
BZOJ3110传送门洛谷P3332传送门
题目描述
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
输入输出格式
输入格式:第一行N,M接下来M行,每行形如1 a b c或2 a b c
输出格式:
输出每个询问的结果
输入输出样例
输入样例#1:2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
输出样例#1:
1
2
1
解法
—->me的整体二分做法传送门树套树
比较容易想清楚的是,一棵线段树只能维护一维的信息
如果一棵线段树以值域来建树,那么这棵树就无法维护下标(位置),同理其他
但是这个题需要区间第K大,位置信息和值域信息都需要保存,因此使用树套树。主树维护值域,小树维护下标(位置),Query和Modify都需要写两个。注意这棵树套树需要动态开点。然后呢,这里是不能主树维护下标而小树维护值域的,如果这样写的话,主树没有办法用永久化标记,要写Pushdown的话复杂度也无法保证(会一层层的往下push)
然后有个比较坑的地方,因为N和M都是50000的规模,那么me可以每次都使区间[1,50000]加上同一个数c,数字c出现的次数就会超过int,这里就需要使用unsigned int或者long long。
另外,针对这个数据,直接用int读入,在查询的时候遇见nd为NULL直接return N也可以过。这样会比使用long long快两秒左右
下面是自带大常数的代码
/************************************************************** Problem: 3110 User: Izumihanako Language: C++ Result: Accepted Time:9160 ms Memory:286396 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <algorithm> using namespace std ; int N , M , upN , downN , a , b ; long long c ; struct downNode{//小树代表下标 int tag ; long long cnt ; downNode *ls , *rs ; void init( ){ cnt = tag = 0 ; } }dw[50005*17*16] , *tdw = dw ; struct upNode{//大树代表值域 upNode *ls , *rs ; downNode *down ; void init(){ down = ++tdw ; down->init() ; } }uw[100005*17] , *tuw = uw , *root ; void up_Newnode( upNode *&nd ){ nd = ++tuw ; nd->init() ; } void down_Newnode( downNode *&nd ){ nd = ++tdw ; nd->init() ; } void down_Update( downNode *nd , int lf , int rg ){ if( !nd->ls ) nd->ls = ++tdw , tdw->init() ; if( !nd->rs ) nd->rs = ++tdw , tdw->init() ; nd->cnt = nd->ls->cnt + nd->rs->cnt + 1LL * nd->tag * ( rg - lf + 1 ) ; } void downAdd( downNode *&nd , int lf , int rg , int L , int R ){ if( !nd ) down_Newnode( nd ) ; if( L <= lf && rg <= R ){ nd->cnt += ( rg - lf + 1 ) ; nd->tag ++ ; return ; } int mid = ( lf + rg ) >> 1 ; if( L <= mid ) downAdd( nd->ls , lf , mid , L , R ) ; if( R > mid ) downAdd( nd->rs , mid+1, rg , L , R ) ; down_Update( nd , lf , rg ) ; } long long downQuery( downNode *nd , int lf , int rg , int L , int R ){ if( !nd ) return 0 ; if( L <= lf && rg <= R ) return nd->cnt ; int mid = ( lf + rg ) >> 1 ; long long rt = 1LL * ( min( R , rg ) - max( L , lf ) + 1 ) * nd->tag ; if( L <= mid ) rt += downQuery( nd->ls , lf , mid , L , R ) ; if( R > mid ) rt += downQuery( nd->rs , mid+1, rg , L , R ) ; return rt ; } void upAdd( upNode *&nd , int lf , int rg , int pos ){ if( !nd ) up_Newnode( nd ) ; downAdd( nd->down , 1 , downN , a , b ) ; if( lf == rg ) return ; int mid = ( lf + rg ) >> 1 ; if( pos <= mid ) upAdd( nd->ls , lf , mid , pos ) ; if( pos > mid ) upAdd( nd->rs , mid+1, rg , pos ) ; } int upQuery( upNode *nd , int lf , int rg , long long K ){ if( lf == rg ) return lf - N ; //if( !nd ) return N ; int mid = ( lf + rg ) >> 1 ; long long Rcnt = ( nd->rs ? downQuery( nd->rs->down , 1 , downN , a , b ) : 0 ) ; if( K <= Rcnt ) return upQuery( nd->rs , mid+1, rg , K ) ; else return upQuery( nd->ls , lf , mid , K - Rcnt ) ; } void solve(){ for( int i = 1 , o ; i <= M ; i ++ ){ scanf( "%d%d%d%lld" , &o , &a , &b , &c ) ; switch(o){ case 1 :{ upAdd( root , 1 , upN , c + N ) ; break; } case 2 : printf( "%d\n" , upQuery( root , 1 , upN , c ) ) ; } } } int main(){ scanf( "%d%d" , &N , &M ) ; upN = N + N ; downN = N ; solve() ; }
相关文章推荐
- [BZOJ3110][Zjoi2013]K大数查询(主席树套线段树||整体二分 )
- 【整体二分+树状数组区间加区间和】BZOJ3110 [Zjoi2013]K大数查询
- bzoj 3110: [Zjoi2013]K大数查询(树套树)
- Bzoj3110: [Zjoi2013]K大数查询
- bzoj3110: [Zjoi2013]K大数查询 树套数
- BZOJ 3110 [Zjoi2013]K大数查询
- 【BZOJ】3110 [Zjoi2013]K大数查询 整体二分+树状数组 || 树套树
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
- 【BZOJ3110】K大数查询(ZJOI2013)-整体二分+线段树
- bzoj 3110 [Zjoi2013]K大数查询 整体二分
- [BZOJ3110][ZJOI2013]K大数查询-CDQ分治-整体二分
- 【BZOJ 3110】 [Zjoi2013]K大数查询(整体二分)
- BZOJ 3110: [Zjoi2013]K大数查询
- bzoj 3110: [Zjoi2013]K大数查询 线段树套线段树
- BZOJ 3110 [Zjoi2013]K大数查询 ——树套树
- 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改
- BZOJ 3110 【ZJOI2013】 K大数查询
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
- Bzoj3110 [Zjoi2013]K大数查询 [整体二分]
- [BZOJ]3110 K大数查询(ZJOI2013)