zoukankan      html  css  js  c++  java
  • HDU 4729 An Easy Problem for Elfness (主席树,树上第K大)

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

    题意:给出一个带边权的图。对于每一个询问(S , T , K , A , B),有两种操作,加一条单位边花费为A,将某条边流量扩展一个单位花费为B,在预算为K的情况下求S到T最大流的最大值。

    http://acm.hdu.edu.cn/showproblem.php?pid=4729

    做法:如果A <= B,很明显只做添加边操作,而且只加在S - T之间,加一条边流量加1。所以结果是初始流量 + K / A。

    如果A > B,则有两种可能,要进行添加边操作,这样的话,显然只添加一条边,就是S - T,然后 不断扩展这条边,那么结果就是初始流量 + K >= A ? 1 : 0 + max (0 , (K - A) / B)。

    否则的话,便是只进行扩展操作。

    第一个问题:怎么求出初始流量,显然是路径中边权最小的值,问题转化为树上第K大,主席树可以解决 。

    第二个问题:只进行扩展操作。显然可以二分,然后判断路径中边权小于这个值的和,以及个数。就能算出花费。但是这样貌似会超时,可以直接在线段树进行逼近。差不多就是用线段树完成二分操作,算出可以增加到的最大限度。

    第一次写的时候是按流量离散化了。。。。然后 发现在第二个问题是不方便实现。。。离散化之后不好统计。然后 发现流量只有1W,就直接建树了。。。连续情况下就考虑了所有情况。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <string>
    #include <vector>
    #include <queue>
    #include <stack>
    #define lowbit(x) (x & (-x))
    #define Key_value ch[ch[root][1]][0] 
    #pragma comment(linker, "/STACK:1024000000,1024000000")    
    using namespace std;
    typedef long long LL;
    const int N = 110005;
    const int M = 2000000;
    struct Edge {
        int v , w , next;
    }edge[N << 1];
    int n , q;
    int start[N] , tot;
    void _add (int u , int v , int w) {
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = start[u];
        start[u] = tot ++;
    }
    void add (int u , int v , int w) {
        _add (u , v , w);
        _add (v , u , w);
    }
    int depth , b[N << 1] , cnt , p[N] , f[N]; 
    int x[N] , m;
    int T[M] , num[M] , sum[M] , nodecnt , lson[M] , rson[M];
    void Init_hash () {
        sort (x , x + n - 1);
        m = unique (x , x + n - 1) - x;
    } 
    int hash (int y) {
        return y;
        return lower_bound (x , x + m , y) - x + 1;
    }
    int bulid (int l , int r) {
        int root = nodecnt ++;
        num[root] = 0;
        sum[root] = 0;
        if (l != r) {
            int mid = (l + r) >> 1;
            lson[root] = bulid (l , mid);
            rson[root] = bulid (mid + 1 , r);
        }
        return root;
    }
    int update (int root , int l , int r , int pos , int val) {
        int newroot = nodecnt ++;
        num[newroot] = num[root] + 1;
        sum[newroot] = sum[root] + val;
        if (l != r) {
            int mid = (l + r) >> 1;
            if (pos <= mid) {
                lson[newroot] = update (lson[root] , l , mid , pos , val);
                rson[newroot] = rson[root];
            }
            else {
                rson[newroot] = update (rson[root] , mid + 1 , r , pos , val);
                lson[newroot] = lson[root]; 
            }
        }
        return newroot;
    }
    // search kth
    int query (int left_root , int right_root , int lca_root , int l , int r , int k) {
        if (l == r) return l;
        int cal = num[lson[left_root]] + num[lson[right_root]] - 2 * num[lson[lca_root]];
        int mid = (l + r) >> 1;
        if (cal >= k) 
            return query (lson[left_root] , lson[right_root] , lson[lca_root] , l , mid , k);
        else 
            return query (rson[left_root] , rson[right_root] , rson[lca_root] , mid + 1 , r , k - cal);
    }
    int query (int left_root , int right_root , int lca_root , int k) {
        int calcnt = num[left_root] + num[right_root] - 2 * num[lca_root];
        int l = 1 , r = m;
        int nowcnt = 0 , nowsum = 0;
        while (l < r) {
            int tmpcnt = num[lson[left_root]] + num[lson[right_root]] - 2 * num[lson[lca_root]];
            int tmpsum = sum[lson[left_root]] + sum[lson[right_root]] - 2 * sum[lson[lca_root]];
            int mid = (l + r) >> 1;
            if (mid * (tmpcnt + nowcnt) - tmpsum - nowsum >= k) {
                r = mid;
                left_root = lson[left_root];right_root = lson[right_root];lca_root = lson[lca_root];
            }
            else {
                l = mid + 1;
                nowcnt += tmpcnt;nowsum += tmpsum;
                left_root = rson[left_root];right_root = rson[right_root];lca_root = rson[lca_root];
            }
        }
        if (k - (nowcnt * l - nowsum) < 0) l --;
        return l + (k - (nowcnt * l - nowsum)) / calcnt;
    }
    void dfs(int u , int pre){  
        int t = ++ depth;  
        b[++ cnt] = t;  
        f[t] = u;  
        p[u] = cnt;  
        for(int i = start[u] ; i != -1 ; i = edge[i].next){  
            int v = edge[i].v , w = edge[i].w;  
            if (v == pre) continue;  
            T[v] = update (T[u] , 1 , m , hash(w) , w);
            dfs (v , u);  
            b[++ cnt] = t;  
        }  
    }  
    int dp[N << 1][20];  
    void Init_rmq(int n){  
        for(int i = 1 ; i <= n ; i++)  
            dp[i][0] = b[i];  
        int m = floor (log (n * 1.0) / log (2.0));    
        for (int j = 1 ; j <= m ; j ++)  
            for (int i = 1;i <= n - (1 << j) + 1 ; i ++)  
                dp[i][j] = min (dp[i][j - 1] , dp[i + (1 << (j - 1))][j - 1]);    
    }  
    int rmq (int l , int r){    
        int k = floor (log ((r - l + 1) * 1.0) / log (2.0));    
        return min (dp[l][k] , dp[r - (1 << k) + 1][k]);    
    }    
    int lca (int a , int b){  
        if (p[a] > p[b]) swap(a , b);  
        return f[rmq (p[a] , p[b])];  
    }  
    
    int main () {
        #ifndef ONLINE_JUDGE
            freopen ("input.txt" , "r" , stdin);
            // freopen ("output.txt" , "w" , stdout);
        #endif
        int t , cas = 0;
        scanf ("%d" , &t);
        while (t --) {
            tot = depth = cnt = nodecnt = 0;
            memset (start , -1 , sizeof(start));
            scanf ("%d %d" , &n , &q);
            for (int i = 1 ; i < n ; i ++) {
                int u , v , w;
                scanf ("%d %d %d" , &u , &v , &w);
                add (u , v , w + 1);
                x[i - 1] = w;
            }
            // Init_hash ();
            m = 10000;
            T[1] = bulid (1 , m);
            dfs (1 , 0);
            Init_rmq (cnt);
            printf ("Case #%d:
    " , ++cas);
            while (q --) {
                int s , e , k , a , b;
                scanf ("%d %d %d %d %d" , &s , &e , &k , &a , &b);
                int initial = query (T[s] , T[e] , T[lca (s , e)] , 1 , m , 1);
                if (a <= b) printf ("%d
    " , initial + k / a - 1);
                else {
                    int ans = initial;
                    if (k >= a) ans = ans + 1 + (k - a) / b;
                    int ret = query (T[s] , T[e] , T[lca (s , e)] , k / b);
                    // cout << initial << " " << ans << " " << ret << endl;
                    printf ("%d
    " , max (ans , ret) - 1);
                }
            }
        }
        return 0;
    }
    



  • 相关阅读:
    九大排序算法
    iOS开发之自定义输入框(利用UITextField及UITextView)
    SQL Server调优系列进阶篇(查询语句运行几个指标值监测)
    C#资源文件与与资源名称字符串之间的互相转化
    EF中用Newtonsoft.Json引发的循环引用问题
    Ajax应用常见的HTTP ContentType设置
    jQuery验证控件jquery.validate.js使用说明+中文API
    今天发现了个轻量级的微信开发的东西。。 记录下
    ASP.NET多文件批量打包下载
    TransactionScope的使用
  • 原文地址:https://www.cnblogs.com/pangblog/p/3327703.html
Copyright © 2011-2022 走看看