UOJ 217 UNR 1 奇怪的線段樹

2021-08-02 10:59:58 字數 2537 閱讀 8684

網路流

我們先來推一波性質:

1、無解當且僅當乙個節點為0且它的兒子為1,有解的話,只有深度極大的節點是有用的(訪問它祖先一定也訪問了)

2、任何乙個區間定位都是一段連續的右兒子+一段連續的左兒子

3、性質2的逆定理成立

實際上,每個右兒子區間左端點一定不同,左兒子區間右端點不同

這意味著每個右兒子後繼唯一,每個左兒子前驅唯一

我們建立網路流模型:右兒子向後繼連inf邊,左兒子向後繼連 inf邊

那麼右兒子轉移到左兒子怎麼辦呢,如果l[i(左)] = r[j(右)] + 1,那麼j -> i連inf邊

剩下的就是點經過次數有上下界了,跑個最小流就好了

還有乙個很顯然的優化就是建虛點,優化邊數

#include #define xx first

#define yy second

#define mp make_pair

#define pb push_back

#define fill( x, y ) memset( x, y, sizeof x )

#define copy( x, y ) memcpy( x, y, sizeof x )

using namespace std;

typedef long long ll;

typedef pair < int, int > pa;

inline int read()

while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();

return sc * f;

}const int maxn = 20005;

const int maxm = 600005;

namespace flow

e[maxm];

int head[maxn], cur[maxn], s, t, e_cnt = 1, q[maxn], ql, qr, dis[maxn];

inline void add(int x, int y, int w) ; head[ x ] = e_cnt; }

inline void addedge(int x, int y, int w)

inline bool bfs()

return dis[ t ];

} inline int dfs(int x, int f)

if( !ret ) dis[ x ] = -1;

return ret;

} inline int dinic() }

using flow::s;

using flow::t;

using flow::addedge;

using flow::dinic;

using flow::inf;

int ch[maxn][2], l[maxn], r[maxn], tot, ss, tt, d[maxn], id[maxn], new_id[maxn], n, rt;

bool type[maxn], leaf[maxn];

vector < int > ls, rs;

inline void build(int &x, int l, int r)

int mid = read();

build( ch[ x ][ 0 ], l, mid ); build( ch[ x ][ 1 ], mid + 1, r );

if( ( type[ ch[ x ][ 0 ] ] || type[ ch[ x ][ 1 ] ] ) && !type[ x ] )

leaf[ x ] = !type[ ch[ x ][ 0 ] ] && !type[ ch[ x ][ 1 ] ] && type[ x ];

ls.pb( ch[ x ][ 0 ] ); rs.pb( ch[ x ][ 1 ] );

}int main()

for( int i = 1 ; i <= n ; i++ ) new_id[ i ] = ( n << 2 ) + i - 1;

for( auto x : rs ) id[ l[ x ] ] = x;

for( auto x : rs ) if( r[ x ] ^ n ) addedge( x << 1 | 1, id[ r[ x ] + 1 ] << 1, inf ), addedge( x << 1 | 1, new_id[ r[ x ] + 1 ], inf );

for( auto x : ls ) id[ r[ x ] ] = x;

for( auto x : ls ) if( l[ x ] ) addedge( id[ l[ x ] - 1 ] << 1 | 1, x << 1, inf ), addedge( new_id[ l[ x ] ], x << 1, inf );

dinic();

addedge( tt, ss, inf );

dinic();

return printf( "%d\n", flow::e[ flow::e_cnt ].flow ), 0;

}

UNR 1 奇怪的線段樹

一道好題,感覺解法非常自然。首先我們只需要考慮一次染色最下面被包含的那些區間,因為把無解判掉以後只要染了乙個節點,它的祖先也一定被染了。然後發現一次染色最下面的那些區間一定是一段連續的左兒子 一段連續的右兒子。證明的話可以看官方題解,感性理解的話不難,同時,任意一段連續的左兒子 右兒子也對應乙個區間...

UOJ 218 UNR 1 火車管理

維護一顆主席樹 火車入棧相當於區間修改,彈棧相當於返回歷史版本 維護線段樹區間求和 ps 之前沒把 放上來 extra的最後乙個點re,orz蒟蒻無能為力 include include include include include const int maxn 600005 const int ...

UOJ 218 UNR 1 火車管理

注意記憶體有些卡,有一些技巧 1.首先對於查詢的線段樹是全域性的,不需要動態開點 2.對於線段樹中的乙個節點 x 如果它的左右兒子都沒有兒子,那麼下一次做區間覆蓋時,就不需要對 x 新建兩個節點 include define lo o 1 define ro o 1 1 using namespac...