Battle over Cities

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 467    Accepted Submission(s): 125

Problem Description
It is vitally important to have all the cities connected by highways in a war, but some of them are destroyed now because of the war. Furthermore,if a city is conquered, all the highways from/toward that city will be closed by the enemy, and we must repair some destroyed highways to keep other cities connected, with the minimum cost if possible.
Given the map of cities which have all the destroyed and remaining highways marked, you are supposed to tell the cost to connect other cities if each city is conquered by the enemy.
 
Input
The input contains multiple test cases. The first line is the total number of cases T (T ≤ 10). Each case starts with a line containing 2 numbers N (0 < N ≤ 20000), and M (0 ≤ M ≤ 100000), which are the total number of cities, and the number of highways, respectively. Then M lines follow, each describes a highway by 4 integers: City1 City2 Cost Status where City1 and City2 are the numbers of the cities the highway connects (the cities are numbered from 1 to N), Cost (0 < Cost ≤ 20000) is the effort taken to repair that highway if necessary, and Status is either 0, meaning that highway is destroyed, or 1, meaning that highway is in use.
Note: It is guaranteed that the whole country was connected before the war and there is no duplicated high ways between any two cities.
 
Output
For each test case, output N lines of integers. The integer in the i-th line indicates the cost to keep the cities connected if the i-th city is conquered by the enemy. In case the cities cannot be connected after the i-th city is conquered by the enemy, output "inf" instead in the corresponding place.
 
Sample Input
3
4 5
1 2 1 1
1 3 1 1
2 3 1 0
2 4 1 1
3 4 2 0
4 5
1 2 1 1
1 3 1 1
2 3 1 0
2 4 1 1
3 4 1 0
3 2
1 2 1 1
1 3 1 1
 
Sample Output
1
2
0
0
1
1
0
0
inf
0
0
 
Author
GUAN, Yao
 
Source
 
Recommend
zhengfeng   |   We have carefully selected several similar problems for you:  3719 3718 3717 3716 3715 

 题解:给定一张N个点,M条边的无向连通图,每条边上有边权w,求删去每一个后的最小生成树。
思路:如果暴力删除每个点后重新建图,跑 Kruskal的话 时间复杂度O(NM),显然不行。
我们考虑先求出没有删点的最小生成树,然后如果我们删除一个点,那么和这个点相连的边全都得去掉,只剩下 该点的邻接点(子节点)和它的父亲节点(可能没有),那么我们只需要在我的子节点连向我的父亲节点的边和我的子树之间的连边中跑一遍MST就行了。

怎么预处理呢?
(1)连接子树之间的边。对于每条连接u,v没有在初始最小生成树里面的边,先求出u,v的lca,则这条边就是连接u的dep[u]-dep[lca]-1个father和v的dep[v]-dep[lca]-1个father的子树的边。用倍增求即可。
(2)连向父亲子树外面的边。对于每条连接u,v没有在初始最小生成树里面的边,先求出u,v的lca,则对于u的dep[u]-dep[lca]-2个father到u这条路径上的所有点,这条边都是连到它们父亲的子树外面的。注意,连向父亲子树外面的边只要取最小的一条即可,于是用倍增+树链剖分进行维护连向父亲子树外面的边的最短长度。对于v同理。
但为什么对每个点把所有可供选择的边预处理出来,再对这些边进行一次最小生成树不会超时呢?我们可以这样来想。因为一次Kruskal并查集的find操作是log(n)的,最坏情况下每条边都会用到一次find,因此重点是求出共有多少条边被用到。连接子树之间的边最多m-n条,连向子树外的边最多n条,所以总共进行m次find。对于m-n条不在最小生成树中的边,都进行预处理,一次预处理倍增是log(n)的,树剖是log(n)*log(n)的。因此,总时间复杂度为O(m log n+ m log n log n)。

参考代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+;
const int M=1e5+;
const int inf=;
int T,n,m,ns,cnt,tim,head[N],to[N<<],nxt[N<<];
int dep[N],fa[N][],siz[N],son[N],dfn[N],pos[N],top[N];
int minn[N],minv[N<<],tag[N<<];
bool use[M];
int s,mst,smst,pa[N],w[N],sont[N],num[N];
struct edge{
int u,v,d;
bool operator < (const edge &x)const{return d<x.d;}
} e[M];
vector<edge> link[N],edges;
void Init()
{
smst=tim=cnt=;
memset(use,,sizeof(use));
memset(head,,sizeof(head));
memset(dep,,sizeof(dep));
memset(fa,,sizeof(fa));
memset(son,,sizeof(son));
memset(sont,,sizeof(sont));
memset(w,,sizeof(w));
memset(minv,,sizeof(minv));
memset(tag,,sizeof(tag));
for(int i=;i<=n;i++) pa[i]=i,link[i].clear();
}
void AddEdge(int u,int v)
{
to[++cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
int Find(int u){return u==pa[u]?u:pa[u]=Find(pa[u]);}
void dfs1(int u)
{
for(int i=;(<<i)<=dep[u];++i)
fa[u][i]=fa[fa[u][i-]][i-];
siz[u]=;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v==fa[u][]) continue;
fa[v][]=u;
dep[v]=dep[u]+;
num[v]=++sont[u];
dfs1(v);
siz[u]+=siz[v];
if(!son[u]||siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(int u,int tp)
{
dfn[u]=++tim;
pos[tim]=u;
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v!=fa[u][]&&v!=son[u]) dfs2(v,v);
}
}
void pushdown(int rt)
{
minv[rt<<]=min(minv[rt<<],tag[rt]);
minv[rt<<|]=min(minv[rt<<|],tag[rt]);
tag[rt<<]=min(tag[rt<<],tag[rt]);
tag[rt<<|]=min(tag[rt<<|],tag[rt]);
tag[rt]=inf;
}
void upd(int rt,int l,int r,int L,int R,int x)
{
if(L<=l&&R>=r)
{
minv[rt]=min(minv[rt],x);
tag[rt]=min(tag[rt],x);
return;
}
if(tag[rt]!=inf) pushdown(rt);
int mid=(l+r)/;
if(L<=mid) upd(rt<<,l,mid,L,R,x);
if(R>mid) upd(rt<<|,mid+,r,L,R,x);
minv[rt]=min(minv[rt<<],minv[rt<<|]);
}
void update(int u,int v,int x)
{
while(top[u]!=top[v])
{
upd(,,n,dfn[top[u]],dfn[u],x);
u=fa[top[u]][];
}
upd(,,n,dfn[v],dfn[u],x);
}
void getmin(int rt,int l,int r)
{
if(l==r)
{
minn[pos[l]]=minv[rt];
return;
}
if(tag[rt]!=inf) pushdown(rt);
int mid=(l+r)/;
getmin(rt<<,l,mid);
getmin(rt<<|,mid+,r);
}
void work(edge &e)
{
int u=e.u,v=e.v,d;
d=dep[u]-dep[v];
for(int i=;(<<i)<=d;i++)
if(d&(<<i)) u=fa[u][i]; if(u==v)
{
u=e.u;
d=dep[u]-dep[v]-;
if(d<) return;
for(int i=;(<<i)<=d;i++)
if(d&(<<i)) u=fa[u][i];
update(e.u,u,e.d);
return;
}
int tmpu=u,tmpv=v;
for(int i=;i>=;i--)
{
if(fa[tmpu][i]!=fa[tmpv][i])
{
tmpu=fa[tmpu][i];
tmpv=fa[tmpv][i];
}
}
link[fa[tmpu][]].push_back((edge){tmpu,tmpv,e.d});
d=dep[e.u]-dep[tmpu]-;
if(d>=)
{
u=e.u;
for(int i=;(<<i)<=d;i++)
if(d&(<<i)) u=fa[u][i];
update(e.u,u,e.d);
}
d=dep[e.v]-dep[tmpv]-;
if(d>=)
{
v=e.v;
for(int i=;(<<i)<=d;i++)
if(d&(<<i)) v=fa[v][i];
update(e.v,v,e.d);
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
Init();
int d,f;
for(int i=;i<=m;i++)
{
scanf("%d%d%d%d",&e[i].u,&e[i].v,&d,&f);
e[i].d=d*(-f);
}
sort(e+,e+m+);
ns=;
for(int i=;i<=m&&ns<n-;i++)
{
int u=Find(e[i].u),v=Find(e[i].v);
if(u!=v)
{
use[i]=true;
pa[v]=u;
ns++;
AddEdge(e[i].u,e[i].v);
AddEdge(e[i].v,e[i].u);
w[e[i].u]+=e[i].d;
w[e[i].v]+=e[i].d;
smst+=e[i].d;
}
}
dfs1(); dfs2(,);
for(int i=;i<=m;i++)
{
if(!use[i])
{
if(dep[e[i].u]<dep[e[i].v])
swap(e[i].u,e[i].v);
work(e[i]);
}
}
getmin(,,n);
for(int i=;i<=n;i++)
{
edges.clear();
s=sont[i];
if(fa[i][])//把所有连向i上面的边加进去
{
++s;
for(int j=head[i];j;j=nxt[j])
{
int v=to[j];
if(v!=fa[i][]&&minn[v]!=inf)
edges.push_back((edge){num[v],s,minn[v]});
}
}
for(int j=;j<link[i].size();j++)//把i的邻接点之间的连边加进去
edges.push_back((edge){num[link[i][j].u],num[link[i][j].v],link[i][j].d});
sort(edges.begin(),edges.end());
mst=;
for(int j=;j<=s;j++) pa[j]=j;
ns=;
for(int j=;j<edges.size()&&ns<s-;j++)
{
int u=Find(edges[j].u),v=Find(edges[j].v);
if(u!=v)
{
pa[v]=u;
ns++;
mst+=edges[j].d;
}
}
if(ns<s-) puts("inf");
else printf("%d\n",smst-w[i]+mst);
}
}
return ;
}

HDU3710 Battle over Cities(最小生成树+树链剖分+倍增+线段树)的更多相关文章

  1. BZOJ 3083 树链剖分+倍增+线段树

    思路: 先随便选个点 链剖+线段树 1操作 就直接改root变量的值 2操作 线段树上改 3操作 分成三种情况 1.new root = xx 整个子树的min就是ans 2. lca(new roo ...

  2. bzoj 4034 [HAOI2015] T2(树链剖分,线段树)

    4034: [HAOI2015]T2 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1536  Solved: 508[Submit][Status] ...

  3. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit ...

  4. poj 3237 Tree(树链剖分,线段树)

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description ...

  5. bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status ...

  6. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4637  Solved: 1726[Submit][Status ...

  7. HDU 4366 Successor(树链剖分+zkw线段树+扫描线)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...

  8. 【BZOJ3531】旅行(树链剖分,线段树)

    [BZOJ3531]旅行(树链剖分,线段树) 题面 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教 ...

  9. 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)

    [BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...

随机推荐

  1. 部署django

    添加uwagi配置文件 在你项目的根目录中创建mysite.xml(名字无所谓),或者创建mysite.ini,输入以下内容: <uwsgi> <socket>127.0.0. ...

  2. 利用Xshell配置ssh免密码登录虚拟机,进行虚拟机与物理机的传输

    先说一下 Xshell如何无密连接虚拟机: ssh登录提供两种认证方式:口令(密码)认证方式和密钥认证方式.其中口令(密码)认证方式是我们最常用的一种,这里介绍密钥认证方式登录到linux的方法.使用 ...

  3. a 标签添加 onclick 事件

    a 标签添加 onclick 事件 <a href="javascript:void(0);" οnclick="js_method()">点击&l ...

  4. 【集合系列】- 深入浅出的分析TreeMap

    一.摘要 在集合系列的第一章,咱们了解到,Map的实现类有HashMap.LinkedHashMap.TreeMap.IdentityHashMap.WeakHashMap.Hashtable.Pro ...

  5. 力扣(LeetCode)删除排序链表中的重复元素 个人题解

    给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次. 这题思路比较简单,同样是快慢针的思路. 用一个整数类型val对应最新的只出现过一次的那个值, 如果节点的下一个节点的值和这个对应则不做别 ...

  6. 工作日志,error parsing query: unable to find time zone

    工作日志,error parsing query: unable to find time zone 坑 Windows 系统使用influxdb数据库,在执行查询语句时提示 ERR: error p ...

  7. 微信小程序-rpx

    rpx 是微信小程序解决自适应屏幕尺寸的尺寸单位.微信小程序规定屏幕的宽度为750rpx. 微信小程序同时也支持rem尺寸单位, rem 规定屏幕的宽度为20rem, 所以 1rem = (750/2 ...

  8. Rust 入门 (二)

    我认为学习计算机语言,应该先用后学,这一节,我们来实现一个猜数字的小游戏. 先简单介绍一个这个游戏的内容:游戏先生成一个1到100之间的任意一个数字,然后我们输入自己猜测的数字,游戏会告诉我们输入的数 ...

  9. Vue组件通信之非父子组件传值

    前言: 如果想要了解非父子关系的组件传值,最好是在了解父传子和子传父的基础上在来了解非父子传值可能会有更透彻的思路. 因为非父子传值是通过定义事件总线来代理实现父传子+子传父从而实现的传值方式. 这是 ...

  10. 网络OSI七层模型以及数据传输过程

    网络OSI七层模型 模型图 国际标准化组织(ISO)制定了osi七层模型,iso规定了各种各样的协议,并且分了7层 每一层的详细信息 具体7层 数据格式 功能与连接方式 典型设备 应用层 Applic ...