zoukankan      html  css  js  c++  java
  • UVA 12161 Ironman Race in Treeland (树分治)

    题意:求树上的一条费用不超过m的路径,使得总长度尽量大。

    人参第一发树分治,紫书上思路讲得比较清晰,这里不再赘述。

    实现的时候,用一个类似时间戟的东西,记录结点首次访问的时间,并保存结点序列。

    合并的时候用map组织有序表。和Defense Lines类似

    复杂度O(nlog^2n)

    #include<bits/stdc++.h>
    using namespace std;
    
    
    const int maxn = 3e4+5;
    int n,m;
    int hd[maxn], nx[maxn<<1], to[maxn<<1], dam[maxn<<1], len[maxn<<1], ec;
    
    inline void add(int u,int v,int D,int L)
    {
        to[ec] = v;
        dam[ec] = D;
        len[ec] = L;
        nx[ec] = hd[u];
        hd[u] = ec++;
    }
    
    int root, best;
    int ct[maxn];
    //best = n
    void GetBaryCenter(int u,int f)
    {
        ct[u] = 1;
        int Mx = 0;
        for(int i = hd[u]; ~i; i = nx[i]){
            if(to[i] != f){
                GetBaryCenter(to[i], u);
                ct[u] += ct[to[i]];
                Mx = max(Mx,ct[to[i]]);
            }
        }
        Mx = max(Mx,n-ct[u]);
        if(Mx < best){
            best = Mx;
            root = u;
        }
    }
    
    #define MP make_pair
    #define fi first
    #define se second
    int C[maxn], L[maxn];
    
    map<int,int> mp;
    map<int,int>::iterator it;
    
    int ans;
    int path[maxn];
    int pre[maxn], dfs_clk;
    //dfs_clk = 0, ans = 0;
    void dfs(int u = root,int f = 0)
    {
        path[dfs_clk] = u;
        pre[u] = dfs_clk++;
        C[u] = 0; L[u] = 0;
        for(int i = hd[u]; ~i; i = nx[i]){
            if(to[i] != f){
                int v = to[i];
                dfs(v,u);
                for(int j = pre[v]; j < dfs_clk ; j++){
                    int x = path[j];
                    C[x] += dam[i];
                    L[x] += len[i];
                }
            }
        }
        //子树都访问完里以后统一处理以保证互不干扰,这样mp就可以设置为全局变量
        mp.clear();
        for(int i = hd[u]; ~i; i = nx[i]){
            int nex = nx[i];
            int lim = ~nex? pre[to[nex]] : dfs_clk;
            if(to[i] != f){
                int v = to[i];
                for(int j = pre[v]; j < lim ; j++){
                    int x = path[j];
                    if(C[x] <= m){
                        ans = max(ans,L[x]);
                        it = mp.upper_bound(m-C[x]);//找到一个key <= C[x]
                        if(it != mp.begin()){
                            ans = max(ans,(--it)->second+L[x]);
                        }
                    }
                }
                for(int j = pre[v]; j < lim ; j++){
                    int x = path[j];
                    if(C[x] <= m){
                        it = mp.lower_bound(C[x]);
                        bool swc = false;
                        if(it == mp.begin() || (swc = true , L[x] > (--it)->se) ){
                            if(swc) it++;
                            while(it != mp.end() && it->se <= L[x]) mp.erase(it++);
                            if(it == mp.end() || it->fi > C[x]) {//lower_bound可能使得it指向key == C[x] 而 val >= L[x]
                                mp.insert(MP(C[x],L[x]));
                            }
                        }
                    }
                }
            }
        }
    }
    
    //#define LOCAL
    int main()
    {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif
        int T, ks = 0; cin>>T;
        while(T--){
            scanf("%d%d",&n,&m);
            memset(hd+1,-1,sizeof(int)*n); ec = 0;
            for(int i = n; --i;){
                int a,b,D,L; scanf("%d%d%d%d",&a,&b,&D,&L);
                add(a,b,D,L); add(b,a,D,L);
            }
            best = n+1;
            GetBaryCenter(1,0);
            dfs_clk = ans = 0;
            dfs();
            printf("Case %d: %d
    ",++ks,ans);
        }
        return 0;
    }
  • 相关阅读:
    Python正则表达式很难?一篇文章搞定他,不是我吹!
    该用Python还是SQL?4个案例教你节省时间
    解决mysql中只能通过localhost访问不能通过ip访问的问题
    MySql按周/月/日分组统计数据的方法
    jquery清空form表单
    eclipse 创建 maven web工程
    微信授权登录
    bootstrap滑动开关插件使用
    去除编译警告@SuppressWarnings注解用法详解(转)
    dataTables添加序号和行选中框
  • 原文地址:https://www.cnblogs.com/jerryRey/p/4858608.html
Copyright © 2011-2022 走看看