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\)发现还是可以用类似链并的思想,这 ...
随机推荐
- Eclipse对Java项目打Jar包
在本Java项目中,如下图一所示,Java项目含有外部依赖Jar包 -- fastjson-1.2.29.jar 包. 在经历了多次的失败后,最后我终于使用 Eclipse 对 "Java ...
- 014.Kubernetes二进制部署docker
一 部署docker 1.1 部署docker组件 docker 运行和管理容器,kubelet 通过 Container Runtime Interface (CRI) 与它进行交互. 1.2 下载 ...
- C++中对C的扩展学习新增内容———面向对象(继承)函数扩展性及虚函数机制
1.c语言中的多态,动态绑定和静态绑定 void do_speak(void(*speak)()) { speak(); } void pig_speak() { cout << &quo ...
- mysql中int、bigint、smallint、tinyint 长度
mysql中int.bigint.smallint.tinyint 长度 bigint -2^63 (-9223372036854775808) 到 2^63-1 (92233720368547758 ...
- nyoj 739 笨蛋难题四
笨蛋难题四 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 这些日子笨蛋一直研究股票,经过调研,终于发现xxx公司股票规律,更可喜的是 笨蛋推算出这家公司每天的股价, ...
- bash:裁剪字符串 ${var:3:2}
1)按照index和长度裁剪变量字符串var=foobar echo ${var:3} -------bar echo ${var:3:2} -------ba 从index为3开始,取两个echo ...
- UNIX env查找技巧
在一些UNIX系统上,也许可以避免硬编码Python解释器的路径,而可以在文件特定的第一行注释中这样写: #!/usr/bin/env python ... script goes here ... ...
- mysql基础之数据类型
一.整型 分为:tinyint .smallint .mediumint .int .bigint 常用的 分为以下三项: tinyint. smallint.int 数据类型 存储范围 字节 tin ...
- ReentreantLock:重入锁
ReentreantLock:重入锁 参考:https://www.cnblogs.com/nullzx/p/4968674.html 一). ReentrantLock与synchronized的区 ...
- 生产者-消费者模型在Hudi中的应用
介绍 生产者-消费者模型用于解耦生产者与消费者,平衡两者之间的能力不平衡,该模型广泛应用于各个系统中,Hudi也使用了该模型控制对记录的处理,即记录会被生产者生产至队列中,然后由消费者从队列中消费,更 ...