【HDU】4729 An Easy Problem for Elfness 可持久化线段树——主席树

来源:互联网 发布:kali windows 双系统 编辑:程序博客网 时间:2024/06/05 00:24

传送门:【HDU】4729 An Easy Problem for Elfness


题目分析:我们发现边的容量最多10000,所以我们可以以边的容量为下标建立主席树,主席树的构造就沿着dfs序构造即可,信息为根到当前节点的信息总汇。节点保存两个信息:这个区间内边的数目,这个区间内边容量之和。(u,v)路径上的信息可以通过根到u的信息+根到v的信息-2*根到lca(u,v)的信息。

初始流量flow很明显,就是路径上的最小树边边权,所以可以用主席树求第K小的方法求最小边容量(也就是第一小)。

然后K的花费我们要分类讨论:

1.a<=b,显然,此时建造一条边(u,v)最划算,ans = flow + k / a。

2.a>b,此时我们有两种方法:

(1)先建一条边(u,v),然后不断扩展这条边的容量,ans1 = flow + (k - a)/ b + 1

(2)将k / b条扩展边权的机会每次优先扩展边权小的边的边权,ans2 = 扩展后路径上最小边的边权

为什么只有这两种情况可以自己思考一下。

最后的ans=max(ans1,ans2)。

(1)好求,不说了,主要是(2)。

对于扩展,我们发现,用线段树二分的方式去寻找节点可以很快的得到答案:如果左子区间可以被完全填满,则我们走右子区间,同时更新临时变量:走过的边数,走过的边的权值和。如果左子区间填不满我们就往左走,走到最后l==r时我们便得到了我们需要的答案:最大可以达到的ans2。此时ans2=l-1(因为当正好填满时我们也是往右区间走了,这样最后l==r时所在的l一定是不能被填满的,l-1一定是可以被填满的,我觉得这样处理起来尤为方便)。


一点吐嘈:

1.至今不会非递归树链剖分,导致不得不C++加扩桟指令。。

2.出题人竟然不卡爆int!!!

3.在听讲座的时候用手机静态调试半个小时竟然AC了!CE无数发以后AC了!太鸡冻了!


代码如下:


#include <map>#include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std ;typedef long long LL ;#pragma comment ( linker , "/STACK:16777216" )#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define clr( a , x ) memset ( a , x , sizeof a )#define mid ( ( l + r ) >> 1 )#define ls ( o << 1 )#define rs ( o << 1 | 1 )#define lson ls , l , m#define rson rs , m + 1 , rconst int MAXN = 100005 ;const int MAXE = 200005 ;const int INF = 0x3f3f3f3f ;struct Edge {int v , c , n ;Edge () {}Edge ( int v , int c , int n ) : v ( v ) , c ( c ) , n ( n ) {}} ;struct Node {Node* c[2] ;LL num , sum ;void push_up () {num = c[0]->num + c[1]->num ;sum = c[0]->sum + c[1]->sum ;}} ;Node pool[MAXN * 50] ;Node* node[MAXN] ;Node* cur ;Node* root[MAXN] ;Edge E[MAXE] ;int H[MAXN] , cntE ;int n , m ;int dep[MAXN] ;int siz[MAXN] ;int pre[MAXN] ;int top[MAXN] ;int son[MAXN] ;void clear () {cntE = 0 ;clr ( H , -1 ) ;cur = pool ;siz[0] = 0 ;pre[1] = 0 ;}void addedge ( int u , int v , int c ) {E[cntE] = Edge ( v , c , H[u] ) ;H[u] = cntE ++ ;}void build ( Node* &o , int l , int r ) {o = cur ++ ;o->num = o->sum = 0 ;if ( l == r ) return ;int m = mid ;build ( o->c[0] , l , m ) ;build ( o->c[1] , m + 1 , r ) ;}void insert ( Node* old , Node* &now , int x , int l , int r ) {now = cur ++ ;if ( l == r ) {now->num = old->num + 1 ;now->sum = old->sum + x ;return ;}int m = mid ;if ( x <= m ) {now->c[1] = old->c[1] ;insert ( old->c[0] , now->c[0] , x , l , m ) ;} else {now->c[0] = old->c[0] ;insert ( old->c[1] , now->c[1] , x , m + 1 , r ) ;}now->push_up () ;}int query_flow ( Node* u , Node* v , Node* lca ) {int l = 0 , r = 10000 ;while ( l < r ) {int m = mid ;int tmp = u->c[0]->num + v->c[0]->num - 2 * lca->c[0]->num ;if ( tmp ) {u = u->c[0] ;v = v->c[0] ;lca = lca->c[0] ;r = m ;} else {u = u->c[1] ;v = v->c[1] ;lca = lca->c[1] ;l = m + 1 ;}}return l ;}LL query ( Node* u , Node* v , Node* lca , int Num ) {int l = 0 , r = 10000 ;int ans = 0 ;LL num = 0 , sum = 0 ;while ( l < r ) {int m = mid ;LL tmp_num = u->c[0]->num + v->c[0]->num - 2 * lca->c[0]->num ;LL tmp_sum = u->c[0]->sum + v->c[0]->sum - 2 * lca->c[0]->sum ;if ( ( num + tmp_num ) * m - ( sum + tmp_sum ) > Num ) {u = u->c[0] ;v = v->c[0] ;lca = lca->c[0] ;r = m ;} else {num += tmp_num ;sum += tmp_sum ;u = u->c[1] ;v = v->c[1] ;lca = lca->c[1] ;l = m + 1 ;}}return l - 1 ;}void dfs ( int u ) {son[u] = 0 ;siz[u] = 1 ;for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v ;if ( v == pre[u] ) continue ;dep[v] = dep[u] + 1 ;pre[v] = u ;insert ( root[u] , root[v] , E[i].c , 0 , 10000 ) ;dfs ( v ) ;siz[u] += siz[v] ;if ( siz[v] > siz[son[u]] ) son[u] = v ;}}void rebuild ( int u , int top_element ) {top[u] = top_element ;if ( son[u] ) rebuild ( son[u] , top_element ) ;for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v ;if ( v != pre[u] && v != son[u] ) {rebuild ( v , v ) ;}}}int get_lca ( int x , int y ) {while ( top[x] != top[y] ) {if ( dep[top[x]] < dep[top[y]] ) swap ( x , y ) ;x = pre[top[x]] ;}if ( dep[x] > dep[y] ) swap ( x , y ) ;return x ;}void solve () {int u , v , k , a , b ;clear () ;scanf ( "%d%d" , &n , &m ) ;rep ( i , 1 , n ) {scanf ( "%d%d%d" , &u , &v , &a ) ;addedge ( u , v , a ) ;addedge ( v , u , a ) ;}build ( root[1] , 0 , 10000 ) ;dfs ( 1 ) ;rebuild ( 1 , 1 ) ;while ( m -- ) {scanf ( "%d%d%d%d%d" , &u , &v , &k , &a , &b ) ;int lca = get_lca ( u , v ) ;LL flow = query_flow ( root[u] , root[v] , root[lca] ) ;if ( a <= b ) printf ( "%I64d\n" , flow + k / a ) ;else {LL ans = 0 ;if ( k >= a ) ans = max ( ans , flow + ( k - a ) / b + 1 ) ;ans = max ( ans , query ( root[u] , root[v] , root[lca] , k / b ) ) ;printf ( "%I64d\n" , ans ) ;}}}int main () {int T , cas = 0 ;scanf ( "%d" , &T ) ;while ( T -- ) {printf ( "Case #%d:\n" , ++ cas ) ;solve () ;}return 0 ;}


0 0
原创粉丝点击