網路流
我們先來推一波性質:
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...