HDU3710 Battle over Cities(最小生成树+树链剖分+倍增+线段树)
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
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.
Note: It is guaranteed that the whole country was connected before the war and there is no duplicated high ways between any two cities.
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
2
0
0
1
1
0
0
inf
0
0
怎么预处理呢?
(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(最小生成树+树链剖分+倍增+线段树)的更多相关文章
- BZOJ 3083 树链剖分+倍增+线段树
思路: 先随便选个点 链剖+线段树 1操作 就直接改root变量的值 2操作 线段树上改 3操作 分成三种情况 1.new root = xx 整个子树的min就是ans 2. lca(new roo ...
- bzoj 4034 [HAOI2015] T2(树链剖分,线段树)
4034: [HAOI2015]T2 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1536 Solved: 508[Submit][Status] ...
- bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 10677 Solved: 4313[Submit ...
- poj 3237 Tree(树链剖分,线段树)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 7268 Accepted: 1969 Description ...
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1272 Solved: 451[Submit][Status ...
- bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4637 Solved: 1726[Submit][Status ...
- HDU 4366 Successor(树链剖分+zkw线段树+扫描线)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...
- 【BZOJ3531】旅行(树链剖分,线段树)
[BZOJ3531]旅行(树链剖分,线段树) 题面 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教 ...
- 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)
[BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...
随机推荐
- C#同级catch块和finally块中全都抛出异常,上一级捕获哪一个?
C#同级catch块和finally块中全都抛出异常,上一级优先捕获finally块中的异常. 测试代码: using System; namespace test { class Program { ...
- .NET Core 对龙芯的支持情况和对 .NET Core 开发嵌入式的思考
目录 .NET Core 对龙芯的支持情况和对 .NET Core 开发嵌入式的思考 一,遗憾的尝试 二,.NET Core在嵌入式下的几点不足 三,.NET Core 龙芯移植的进展和资料 .NET ...
- java多线程与线程并发五:多个线程访问共享对象和数据的方式
本节的内容主要是对前面几节提到的线程间共享数据的方式做一个总结. 线程之间共享数据有以下几种方式: 1.如果每个线程执行的代码相同,可以使用同一个Runnable对象. 2.如果每个线程执行的代码不同 ...
- T-SQL Part VIII: CROSS APPLY, OUTER APPLY
除了CROSS JOIN, INNER JOIN, OUTER JOIN之外,T-SQL还提供了CROSS APPLY和OUTER APPLY这两个较为另类的Set操作符. 首先来看CROSS APP ...
- PHP中跳出循环break,continue,return,exit的区别
1. return 语句的作用 (1) return 从当前的方法中退出,返回到该调用的方法的语句处,继续执行. (2) return 返回一个值给调用该方法的语句,返回值的数 ...
- lqb 入门训练 圆的面积 (PS: PI的精确计算方法 atan(1.0) * 4)
入门训练 圆的面积 时间限制:1.0s 内存限制:256.0MB 问题描述 给定圆的半径r,求圆的面积. 输入格式 输入包含一个整数r,表示圆的半径. 输出格式 输出一行,包含一个实数,四 ...
- nyoj 65-另一种阶乘问题 (Java 高精度)
65-另一种阶乘问题 内存限制:64MB 时间限制:3000ms 特判: No 通过数:16 提交数:18 难度:1 题目描述: 大家都知道阶乘这个概念,举个简单的例子:5!=1*2*3*4*5.现在 ...
- Test Complete 的自动化测试 --- 三角形
Test Complete 的自动化测试 --- 三角形 PS:工具:Test Complete , OS:win 10 这里做三角形的测试与上一篇博客做计算器的测试大致一样,都是对.exe的执行文件 ...
- gdb(ddd,kdevelop等)调试ZeroIce开发的应用程序,中断信号引起的问题
不作文,只记要点. 1.Ice::Application的程序框架默认对SIGHUP, SIGINT, SIGTERM进行处理.目的就是捕捉Ctrl+C发出信号有序地结束程序.这个功能扰乱了我们使用g ...
- SpringBoot学习(一)—— idea 快速搭建 Spring boot 框架
简介 优点 Spring Boot 可以以jar包的形式独立运行,运行一个Spring Boot 项目只需要通过 java -jar xx.jar 来运行. Spring Boot 可以选择内嵌Tom ...