UVa 12587 Reduce the Maintenance Cost(Tarjan + 二分 + DFS)

题意:n个城市(n <= 10000), 有m条边(m <= 40000),每一个城市有一个维护费用Cost(i),除此之外,每条边的维修费用为去掉该边后不能通信的城市对数与边权的积。这个费用要加到这条边的两端城市的某一个,问你全部城市的最大费用的最小值。、

思路:首先边的费用能够通过Tarjan求桥之后求得(利用桥的性质),然后就是二分答案了!对于每一个点,假设有个儿子不能维护。那么不可行,否则。试着让儿子去维护边权,假设不可行,仅仅能让父亲承担。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long LL;
const int maxn = 10000+10;
const int maxm = 40000+10;
LL cost[maxn];
int head[maxn];
int n,m;
int dfn[maxn],lown[maxn];
bool CanE[maxn];
int cnt[maxm];
LL ans;
int nume,dfs_clock;
bool vis[maxn];
bool isBridge[maxm];
vector<int> sta;
struct edge{
    int u,v,w,nxt;
}e[maxm];

void Tarjan(int u,int fa) {
    lown[u] = dfn[u] = dfs_clock++;
    sta.push_back(u);
    for(int i = head[u]; i ; i = e[i].nxt) {
        int v = e[i].v;
        if(v==fa) continue;
        if(!dfn[v]) {
            Tarjan(v,u);
            lown[u] = min(lown[u],lown[v]);
            if(lown[v] > dfn[u]) {
                isBridge[i] = isBridge[i^1] = true;
                cnt[i] = cnt[i^1] = dfs_clock-dfn[v];
            }
        }else {
            lown[u] = min(lown[u],dfn[v]);
        }
    }
}
bool dfs(int u,LL s,LL x) {
    vis[u] = true;
    LL ts = cost[u];
    int sz = sta.size();
    for(int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].v, w = e[i].w;
        if(isBridge[i] && !vis[v]) {
            LL tmp = (LL)w*cnt[i]*(sz-cnt[i]);
            if(!dfs(v,tmp,x)) return false;
            if(!CanE[v]) ts += tmp;
        }
    }
    if(ts > x) return false;
    if(ts+s <= x)  CanE[u] = true;
    return true;
}
bool can(LL x) {
    int len = sta.size();
    memset(CanE,false,sizeof CanE);
    for(int i = 0; i < len; i++) vis[sta[i]] = false;
    for(int i = 0; i < len; i++) {
        int t = sta[i];
        if(vis[t]) continue;
        if(!dfs(t,0,x)) return false;
    }
    return true;
}
void init() {
    nume = 1;
    ans = 0;
    dfs_clock = 1;
    memset(head,0,sizeof head);
    memset(isBridge,false,sizeof isBridge);
    memset(vis,false,sizeof vis);
    memset(dfn,0,sizeof dfn);
    memset(lown,0,sizeof lown);
    memset(CanE,false,sizeof CanE);
    sta.clear();
}
void addedge(int u,int v,int w) {
    e[++nume].nxt = head[u];
    e[nume].u = u;
    e[nume].v = v;
    e[nume].w = w;
    head[u] = nume;
}
void solve() {
    for(int i = 1; i <= n; i++) {
        if(!dfn[i]) {
            sta.clear();
            Tarjan(i,-1);
            LL L = ans,R = 1e10;
            while(L <= R) {
                LL mid = (L+R)/2;
                if(can(mid)) {
                    R = mid-1;
                }else{
                    L = mid+1;
                }
            }
            ans = max(ans,L);
        }
    }
    printf("%lld\n",ans);
}
int main(){

    int ncase,T=1;
    cin >> ncase;
    while(ncase--) {
        init();
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++) {
            scanf("%lld",&cost[i]);
            ans = max(ans,cost[i]);
        }
        for(int i = 0; i < m; i++) {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            addedge(a,b,c);
            addedge(b,a,c);
        }
        printf("Case %d: ",T++);
        solve();
    }
    return 0;
}
时间: 2024-10-01 07:51:55

UVa 12587 Reduce the Maintenance Cost(Tarjan + 二分 + DFS)的相关文章

POJ 2942 - Knights of the Round Table(双连通图 Tarjan + 二分判定)

POJ 2942 - Knights of the Round Table(双连通图 Tarjan + 二分判定) ACM 题目地址: POJ 2942 - Knights of the Round Table 题意: 有N个骑士,给出某些骑士之间的仇恨关系,骑士们开会时会围坐在一个圆桌旁.一次会议能够顺利举行,要满足两个条件: 任意相互憎恨的两个骑士不能相邻 开会人数为大于2的奇数 若某个骑士任何会议都不能参加,那么就必须将他踢出,给出骑士之间的仇恨关系,问最少需要踢出多少个骑士? 分析: 把

UVA - 11478 Halum (最短路应用+二分)

Description   Problem H Halum Time Limit : 3 seconds     You are given a directed graph G(V,E) with a set of vertices and edges. Each edge (i,j) that connects some vertex i to vertex j has an integer cost associated with that edge. Define the operati

UVA 1345 - Jamie&#39;s Contact Groups(二分+最大流)

UVA 1345 - Jamie's Contact Groups 题目链接 题意:给定一些人,每个人有一个分组,现在要每个人选一个分组,使得所有分组中最大的人数最小,问这个最小值是多少 思路:二分答案,然后利用最大流去判定,源点往每个人建一条边容量为1,每个人往各自的分组建一条边,容量为1,分组向汇点建一条边,容量为二分出来的值,这样跑一下最大流如果最大流等于n,就是能满足 代码: #include <cstdio> #include <cstring> #include <

[BZOJ 1082] [SCOI2005] 栅栏 【二分 + DFS验证(有效剪枝)】

题目链接:BZOJ - 1082 题目分析 二分 + DFS验证. 二分到一个 mid ,验证能否选 mid 个根木棍,显然要选最小的 mid 根. 使用 DFS 验证,因为贪心地想一下,要尽量先用提供的小的木木棍,尽量先做出需要的大的木棍,所以要先将提供的木棍和需要的木棍都排序. DFS 的时候是按照需要的木棍从大到小的顺序一层一层搜,每一层上是按照从小到大的顺序枚举提供的木棍.(当然枚举的时候已经不一定是从小到大了,有些木棍已经被截掉了一些.) 要使用两个有效的剪枝: 1)如果下一层的木棍和

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

Uva 12009 平方数尾数与自身相同 dfs 构造

题目链接:点击打开链接 题意:rt 思路:从最低位开始构造,若x位的平方数是自身则继续构造. mark: #pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack>

51nod1307(暴力树剖/二分&amp;dfs/并查集)

题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307 题意: 中文题诶~ 思路: 解法1:暴力树剖 用一个数组 num[i] 维护编号为 i 的边当前最大能承受的重量. 在加边的过程中根据给出的父亲节点将当前边所在的链上所有边的num都减去当前加的边的重量, 注意当前边也要减自重. 那么当num首次出现负数时加的边号即位答案: 事实上这个算法的时间复杂度是O(n^2)的, 不过本题并没有出那种退化成单链的

Codeforces 901C Bipartite Segments(Tarjan + 二分)

题目链接  Bipartite Segments 题意  给出一个无偶环的图,现在有$q$个询问.求区间$[L, R]$中有多少个子区间$[l, r]$ 满足$L <= l <= r <= R$,并且一个只包含$l$到$r$这些点的无向图为二分图. 因为整张图没有偶环,所以在这道题中如果某个无向图没有环,那个这个无向图就是二分图 Tarjan求出每个环的标号最小点和标号最大点. 令$f[i]$为能保证$[i, j]$这个区间构成的图都是二分图的$j$的最大值,则$f[i]$是不下降的 当

luogu CF901C Bipartite Segments |Tarjan+二分

题意翻译 给你一个有nnn个点的无向图,没有偶环.我们把节点标记为1..n1..n1..n. 你需要回答qqq个询问,每一个询问由一个区间L,R组成,你需要计算出有多少个点对x,y,满足由[x,y]之间的所有点组成的子图是一个二分图. 输入数据第一行两个整数 n,mn,mn,m (1≤n≤3×105,1≤m≤3×1051\le n\le 3\times 10^5,1\le m\le 3\times10^51≤n≤3×105,1≤m≤3×105)代表点数和边数 接下来的mmm行,每行两个整数,表示