传送门:【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 , r const 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 ; }