数据结构之fhq-treap——Chef and Sets,[HNOI2012]永无乡,Play with Chain,[NOI2005]维修数列(结构体版代码)
因?yàn)榉浅0?#xff0c;所以主要是代碼
- Tyvj 1728 普通平衡樹(shù)
- Chef and Sets
- [HNOI2012]永無(wú)鄉(xiāng)
- Play with Chain
- [NOI2005]維修數(shù)列
題目很水,所以可能會(huì)出現(xiàn)代碼部分細(xì)節(jié)出鍋,但確實(shí)這些代碼是能過(guò)得
還請(qǐng)多多包涵
Tyvj 1728 普通平衡樹(shù)
luogu3369
#include <cstdio> #include <algorithm> using namespace std; #define maxn 100005 struct node {int l, r, key, val, siz, cnt; }t[maxn]; int Size, root;int Newnode( int x ) {t[++ Size].val = x;t[Size].key = rand();t[Size].siz = t[Size].cnt = 1;return Size; }void pushup( int x ) {t[x].siz = t[t[x].l].siz + t[t[x].r].siz + t[x].cnt; }void split( int now, int val, int &x, int &y ) {if( ! now ) x = y = 0;else {if( t[now].val <= val ) {x = now;split( t[now].r, val, t[now].r, y );pushup( x );}else {y = now;split( t[now].l, val, x, t[now].l );pushup( y );}} }int merge( int x, int y ) {if( ! x or ! y ) return x + y;if( t[x].key < t[y].key ) {t[x].r = merge( t[x].r, y );pushup( x );return x;}else {t[y].l = merge( x, t[y].l );pushup( y );return y;} }void add( int x ) {int l, r, L, R;split( root, x, l, r );split( l, x - 1, L, R );if( R ) {t[R].cnt ++;pushup( R );root = merge( merge( L, R ), r );}else {int t = Newnode( x );root = merge( merge( L, t ), r );} }void del( int x ) {int l, r, L, R;split( root, x, l, r );split( l, x - 1, L, R );if( R and t[R].cnt > 1 ) {t[R].cnt --;pushup( R );root = merge( merge( L, R ), r );}else root = merge( L, r ); }void find_rank( int x ) {int l, r;split( root, x - 1, l, r );printf( "%d\n", t[l].siz + 1 );root = merge( l, r ); }void rank_find( int rt, int x ) {while( 1 ) {if( t[t[rt].l].siz >= x ) rt = t[rt].l;else if( t[t[rt].l].siz + t[rt].cnt >= x ) {printf( "%d\n", t[rt].val );return;}else x -= ( t[t[rt].l].siz + t[rt].cnt ), rt = t[rt].r;} }void find_pre( int x ) {int l, r;split( root, x - 1, l, r );rank_find( l, t[l].siz );root = merge( l, r ); }void find_suf( int x ) {int l, r;split( root, x, l, r );rank_find( r, 1 );root = merge( l, r ); }int main() {int n;scanf( "%d", &n );while( n -- ) {int opt, x;scanf( "%d %d", &opt, &x );switch( opt ) {case 1 : { add( x ); break; }case 2 : { del( x ); break; }case 3 : { find_rank( x ); break; }case 4 : { rank_find( root, x ); break; }case 5 : { find_pre( x ); break; }case 6 : { find_suf( x ); break; }}}return 0; }Chef and Sets
codechef
每次暴力的合并兩個(gè)集合
為了維護(hù)權(quán)值的小根堆性質(zhì),只能從集合中一個(gè)一個(gè)的并到另一個(gè)集合里面去
具體而言
- 每次操作集合個(gè)數(shù)較小的其中一個(gè)數(shù)
- 然后根據(jù)這個(gè)數(shù)的權(quán)值,分裂較大集合
- 把這個(gè)數(shù)并到大集合中,從小集合中刪除
- 重復(fù)這樣的操作,直到小集合為空
看似暴力,但是一共就nnn個(gè)數(shù)的集合并,沒(méi)有新增的數(shù)
最壞就是nlog?nn\log nnlogn的(每次就個(gè)數(shù)相同的兩個(gè)集合合并)
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define maxn 300005 struct node { int siz, l, r, val, key; }t[maxn]; int root[maxn];void pushup( int x ) {t[x].siz = t[t[x].l].siz + t[t[x].r].siz + 1; }void split_val( int now, int val, int &x, int &y ) {if( ! now ) x = y = 0;else {if( t[now].val <= val ) {x = now;split_val( t[now].r, val, t[now].r, y );pushup( x );}else {y = now;split_val( t[now].l, val, x, t[now].l );pushup( y );}} }void split_id( int now, int cnt, int &x, int &y ) {if( ! now ) x = y = 0;else {if( t[t[now].l].siz + 1 <= cnt ) {x = now;split_id( t[now].r, cnt - ( t[t[now].l].siz + 1 ), t[now].r, y );pushup( x );}else {y = now;split_id( t[now].l, cnt, x, t[now].l );pushup( y );}} }int merge( int x, int y ) {if( ! x or ! y ) return x + y;if( t[x].key < t[y].key ) {t[x].r = merge( t[x].r, y );pushup( x );return x;}else {t[y].l = merge( x, t[y].l );pushup( y );return y;} }void find_kth( int now, int x ) {while( 1 ) {if( t[t[now].l].siz >= x ) now = t[now].l;else if( t[t[now].l].siz + 1 == x ) {printf( "%d\n", t[now].val );return;}else x -= ( t[t[now].l].siz + 1 ), now = t[now].r;} }int main() {int n, Q;scanf( "%d %d", &n, &Q );for( int i = 1;i <= n;i ++ )t[i].siz = 1, t[i].val = root[i] = i, t[i].key = rand();char opt[10]; int a, b, k;while( Q -- ) {scanf( "%s %d", opt, &a );if( opt[0] == 'U' ) {scanf( "%d", &b );++ n;if( t[root[a]].siz < t[root[b]].siz )swap( a, b );root[n] = root[a];int l, r, L, R;while( root[b] ) {split_id( root[b], 1, l, r );split_val( root[n], t[l].val, L, R );root[n] = merge( merge( L, l ), R );root[b] = r;}}else {scanf( "%d", &k );find_kth( root[a], k );}}return 0; }[HNOI2012]永無(wú)鄉(xiāng)
luogu3224
與上一題幾乎是一模一樣
不過(guò)刁鉆了一下,給的是集合中某一個(gè)點(diǎn),并不一定直接是集合的根
其實(shí)也米有什么變化
套一個(gè)并查集記錄每個(gè)點(diǎn)所在集合的根就行了
#include <cstdio> #include <algorithm> using namespace std; #define maxn 500005 struct node {int l, r, id, val, key, siz; }t[maxn]; int root[maxn], p[maxn], f[maxn];int find( int x ) {return x == f[x] ? x : f[x] = find( f[x] ); }void pushup( int x ) {t[x].siz = t[t[x].l].siz + t[t[x].r].siz + 1; }void split_val( int now, int val, int &x, int &y ) {if( ! now ) x = y = 0;else {if( t[now].val <= val ) {x = now;split_val( t[now].r, val, t[now].r, y );pushup( x );}else {y = now;split_val( t[now].l, val, x, t[now].l );pushup( y );}} }void split_id( int now, int cnt, int &x, int &y ) {if( ! now ) x = y = 0;else {if( t[t[now].l].siz + 1 <= cnt ) {x = now;split_id( t[now].r, cnt - ( t[t[now].l].siz + 1 ), t[now].r, y );pushup( x );}else {y = now;split_id( t[now].l, cnt, x, t[now].l );pushup( y ); }} }int merge( int x, int y ) {if( ! x or ! y ) return x + y;if( t[x].key < t[y].key ) {t[x].r = merge( t[x].r, y );pushup( x );return x; }else {t[y].l = merge( x, t[y].l );pushup( y );return y;} }void find_kth( int rt, int x ) {while( 1 ) {if( t[t[rt].l].siz >= x ) rt = t[rt].l;else if( t[t[rt].l].siz + 1 == x ) {printf( "%d\n", t[rt].id );return;}else x -= ( t[t[rt].l].siz + 1 ), rt = t[rt].r;} }int main() {int n, m, Q, x, y, k;char opt[10];scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ )scanf( "%d", &p[i] );for( int i = 1;i <= n;i ++ ) {t[i].val = p[i];t[i].key = rand();t[i].siz = 1;t[i].id = i;root[i] = i;f[i] = i;}for( int i = 1;i <= m;i ++ ) {scanf( "%d %d", &x, &y );if( find( x ) == find( y ) ) continue;x = find( x );y = find( y );if( t[root[x]].siz < t[root[y]].siz ) swap( x, y );root[++ n] = root[x];f[n] = n;while( root[y] ) {int l, r, L, R;split_id( root[y], 1, l, r );split_val( root[n], t[l].val, L, R );root[n] = merge( merge( L, l ), R );root[y] = r;}f[find( x )] = f[find( y )] = n;}scanf( "%d", &Q );while( Q -- ) {scanf( "%s %d", opt, &x );if( opt[0] == 'Q' ) {scanf( "%d", &k );x = find( x );if( t[root[x]].siz < k ) printf( "-1\n" );else find_kth( root[x], k );}else {scanf( "%d", &y );if( find( x ) == find( y ) ) continue;x = find( x );y = find( y );if( t[root[x]].siz < t[root[y]].siz ) swap( x, y );root[++ n] = root[x];f[n] = n;while( root[y] ) {int l, r, L, R;split_id( root[y], 1, l, r );split_val( root[n], t[l].val, L, R );root[n] = merge( merge( L, l ), R );root[y] = r;}f[find( x )] = f[find( y )] = n;}}return 0; }Play with Chain
HDU3487
#include <cstdio> #include <vector> #include <iostream> #include <algorithm> using namespace std; #define maxn 300005 vector < int > ans; struct node {int l, r, val, key, siz, tag; }t[maxn];void pushup( int x ) {t[x].siz = t[t[x].l].siz + t[t[x].r].siz + 1; }void pushdown( int x ) {if( ! t[x].tag ) return;swap( t[x].l, t[x].r );t[t[x].l].tag ^= 1;t[t[x].r].tag ^= 1;t[x].tag = 0; }void split( int now, int cnt, int &x, int &y ) {if( ! now ) x = y = 0;else {pushdown( now );if( t[t[now].l].siz + 1 <= cnt ) {x = now;split( t[now].r, cnt - ( t[t[now].l].siz + 1 ), t[now].r, y );pushup( x );}else {y = now;split( t[now].l, cnt, x, t[now].l );pushup( y );}} }int merge( int x, int y ) {if( ! x or ! y ) return x + y;if( t[x].key < t[y].key ) {pushdown( x );t[x].r = merge( t[x].r, y );pushup( x );return x;}else {pushdown( y );t[y].l = merge( x, t[y].l );pushup( y );return y;} }void print( int x ) {if( ! x ) return;pushdown( x );print( t[x].l );ans.push_back( t[x].val );print( t[x].r ); }int main() {int n, m, a, b, c; char opt[10];while( scanf( "%d %d", &n, &m ) ) {if( n == -1 and m == -1 ) return 0;for( int i = 1;i <= n;i ++ ) {t[i].l = t[i].r = t[i].tag = 0;t[i].siz = 1;t[i].val = i;t[i].key = rand();}int rt = 0;for( int i = 1;i <= n;i ++ )rt = merge( rt, i );int l, r, L, R;while( m -- ) {scanf( "%s %d %d", opt, &a, &b );if( opt[0] == 'C' ) {scanf( "%d", &c );split( rt, a - 1, l, r );split( r, b - a + 1, L, R );rt = merge( l, R );split( rt, c, l, r );rt = merge( merge( l, L ), r );}else {split( rt, a - 1, l, r );split( r, b - a + 1, L, R );t[L].tag ^= 1;rt = merge( l, merge( L, R ) );}}print( rt );printf( "%d", ans[0] );for( int i = 1;i < ans.size();i ++ )printf( " %d", ans[i] );printf( "\n" );ans.clear();}return 0; }[NOI2005]維修數(shù)列
BZOJ1500
把線段樹(shù)的所有計(jì)算方法全都搬到平衡樹(shù)上就行
#include <queue> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define maxn 500005 #define lson t[now].l #define rson t[now].r #define inf 0x3f3f3f3f queue < int > q; struct node {int l, r, siz, val, key, reverse, cover, sum, max_sum, max_l, max_r; }t[maxn]; int Size;int MakeNode( int x ) {int now;if( ! q.empty() ) now = q.front(), q.pop();else now = ++ Size;lson = 0; //左兒子 rson = 0; //右兒子 t[now].reverse = 0; //翻轉(zhuǎn)標(biāo)記 t[now].cover = inf; //覆蓋標(biāo)記 t[now].val = x; //權(quán)值 t[now].sum = x; //區(qū)間和 t[now].max_l = x; //從區(qū)間左端點(diǎn)開(kāi)始連續(xù)最大子段和 t[now].max_r = x; //從區(qū)間右端點(diǎn)開(kāi)始連續(xù)最大子段和 t[now].max_sum = x; //區(qū)間最大子段和 t[now].key = rand(); //修正值/鍵值t[now].siz = 1; //子樹(shù)大小 return now; }void pushup( int now ) {if( ! now ) return;t[now].siz = t[lson].siz + t[rson].siz + 1;t[now].sum = t[lson].sum + t[rson].sum + t[now].val;t[now].max_sum = max( max( t[lson].max_sum, t[rson].max_sum ), max( 0, t[lson].max_r ) + t[now].val + max( 0, t[rson].max_l ) );t[now].max_l = max( t[lson].max_l, t[lson].sum + t[now].val + max( 0, t[rson].max_l ) );t[now].max_r = max( t[rson].max_r, t[rson].sum + t[now].val + max( 0, t[lson].max_r ) ); }void modify( int now, int val ) {t[now].val = val;t[now].cover = val;t[now].sum = t[now].siz * val;t[now].max_l = max( 0, t[now].sum );t[now].max_r = max( 0, t[now].sum );t[now].max_sum = max( val, t[now].sum ); }void operation( int now ) {swap( lson, rson );swap( t[now].max_l, t[now].max_r );t[now].reverse ^= 1; }void pushdown( int now ) {if( t[now].reverse ) {if( lson ) operation( lson );if( rson ) operation( rson );t[now].reverse = 0;}if( t[now].cover ^ inf ) {if( lson ) modify( lson, t[now].cover );if( rson ) modify( rson, t[now].cover );t[now].cover = inf;} }void split( int now, int cnt, int &x, int &y ) {if( ! now ) x = y = 0;else {pushdown( now );if( t[lson].siz + 1 <= cnt) {x = now;split( rson, cnt - ( t[lson].siz + 1 ), rson, y );pushup( x );}else {y = now;split( lson, cnt, x, lson );pushup( y );}} }int merge( int x, int y ) {if( ! x or ! y ) return x + y;pushdown( x );pushdown( y );if( t[x].key < t[y].key ) {t[x].r = merge( t[x].r, y );pushup( x );return x;}else {t[y].l = merge( x, t[y].l );pushup( y );return y;} }void inque( int now ) {if( ! now ) return;q.push( now );inque( lson );inque( rson ); }int n, m, rt, l, r, L, R, k, pos, x; char opt[10]; int main() {scanf( "%d %d", &n, &m );t[0].val = t[0].max_sum = -inf;for( int i = 1;i <= n;i ++ ) {scanf( "%d", &x );rt = merge( rt, MakeNode( x ) );}while( m -- ) {scanf( "%s", opt );switch( opt[2] ) {case 'S' : { //INSERTscanf( "%d %d", &pos, &k );split( rt, pos, l, r );for( int i = 1;i <= k;i ++ ) {scanf( "%d", &x );l = merge( l, MakeNode( x ) );}rt = merge( l, r );break;}case 'L' : { //DELETEscanf( "%d %d", &pos, &k );split( rt, pos - 1, l, r );split( r, k, L, R );rt = merge( l, R );inque( L );break;}case 'K' : { //MAKE-SAMEscanf( "%d %d %d", &pos, &k, &x );split( rt, pos - 1, l, r );split( r, k, L, R );modify( L, x );rt = merge( l, merge( L, R ) );break;}case 'V' : { //REVERSEscanf( "%d %d", &pos, &k );split( rt, pos - 1, l, r );split( r, k, L, R );operation( L );rt = merge( l, merge( L, R ) );break;}case 'T' : { //GET_SUMscanf( "%d %d", &pos, &k );split( rt, pos - 1, l, r );split( r, k, L, R );printf( "%d\n", t[L].sum );rt = merge( l, merge( L, R ) );break;}case 'X' : { //MAX-SUM;printf( "%d\n", t[rt].max_sum );break;}}}return 0; }只需要相信:只要多pushdown就不會(huì)出現(xiàn)標(biāo)記與點(diǎn)不對(duì)應(yīng)的情況,那么這與線段樹(shù)有什么區(qū)別呢??
總結(jié)
以上是生活随笔為你收集整理的数据结构之fhq-treap——Chef and Sets,[HNOI2012]永无乡,Play with Chain,[NOI2005]维修数列(结构体版代码)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 华硕K55VD简单拆机
- 下一篇: 在Arcmap中加载互联网地图资源的4种