【BZOJ-2888】资源运输 LCT + 启发式合并
2888: 资源运输
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 63 Solved: 33
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
Q
A 1 2
A 4 5
A 6 7
A 3 4
Q
A 2 5
A 6 8
A 4 6
Q
Sample Output
4
12
【样例解释】
1.开始所有城市互不联通,每个城市都是资源集合处,费用为0;
2.后来分别把城市1、城市4、城市7、城市8设立为资源集合处,费用为4;
3.最后把城市4设立为资源集合处,费用为12。
HINT
N<=40000,M<=80000
Source
Solution
首先可以发现,对于森林中的每棵树,资源集合处都应该是重心。
所以对森林,维护每个树的重心。
问题在于合并两棵树时快速得到新树的重心,只能暴力重构。
不过考虑把小的一棵树拆开,一个一个点的加入大的一棵树中,这样就可以得到新树的重心了(保持原有重心或者向加点方向移动一步)。
维护答案需要维护子树到重心的距离和,那么加入一个新点,相当于链上加一个等差数列。
等差数列标记显然是可以合并的,注意下放的时候,如果向左子树下放则需要加上右子树的贡献,因为LCT中的右子树是其左子树的后代。
这样启发式合并的复杂度就是$O(Nlog^{2}N)$,不过直接写数组的常数有点略大会TLE..所以改成了结构体。
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
} #define MAXN 40010 int N,M,ans; struct EdgeNode{
int next,to;
}edge[MAXN<<1];
int head[MAXN],cnt=1;
inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);} namespace LCT{ int sz;
struct LCTNode{
int son[2],fa,size,tag,val,a1,d,sum;
}t[MAXN]; inline bool isroot(int x) {return t[t[x].fa].son[0]!=x&&t[t[x].fa].son[1]!=x || !t[x].fa;} inline void Update(int x) {if (!x) return; t[x].size=t[t[x].son[0]].size+t[t[x].son[1]].size+1;} inline void Modify(int x,int v) {if (!x) return; t[x].tag+=v; t[x].val+=v;} inline void Change(int x,int _a1,int _d) {if (!x) return; t[x].a1+=_a1; t[x].d+=_d; t[x].sum+=_a1+t[t[x].son[1]].size*_d;} inline void Pushdown(int x)
{
if (!x) return;
if (t[x].tag) Modify(t[x].son[0],t[x].tag),Modify(t[x].son[1],t[x].tag),t[x].tag=0;
if (t[x].d) Change(t[x].son[0],t[x].a1+(t[t[x].son[1]].size+1)*t[x].d,t[x].d),Change(t[x].son[1],t[x].a1,t[x].d),t[x].a1=t[x].d=0;
} inline void Rotate(int x)
{
int y=t[x].fa,w=t[y].son[1]==x,z=t[y].fa;
t[y].son[w]=t[x].son[w^1];
if (t[x].son[w^1]) t[t[x].son[w^1]].fa=y;
if (t[z].son[0]==y) t[z].son[0]=x; else if (t[z].son[1]==y) t[z].son[1]=x;
t[x].fa=z; t[y].fa=x; t[x].son[w^1]=y;
Update(y);
} int stack[MAXN];
inline void Splay(int x)
{
int tmp=x,top=0,y; stack[++top]=x;
while (!isroot(tmp)) stack[++top]=tmp=t[tmp].fa;
while (top) Pushdown(stack[top--]);
while (!isroot(x)) {
y=t[x].fa;
if (!isroot(y))
if ((t[t[y].fa].son[0]==y)^(t[y].son[0]==x)) Rotate(x);
else Rotate(y);
Rotate(x);
}
Update(x);
} inline void Access(int x) {for (int y=0; x; y=x,x=t[x].fa) Splay(x),t[x].son[1]=y,Update(x);} inline int Root(int x) {Access(x); Splay(x); while(t[x].son[0]) x=t[x].son[0]; return x;} inline void Add(int x,int y)
{
t[x].fa=y; t[x].son[0]=t[x].son[1]=t[x].val=t[x].tag=t[x].sum=t[x].a1=t[x].d=0; t[x].size=1;
y=Root(y); Access(x); Splay(y);
Modify(y,1); Change(y,0,1);
for (x=t[y].son[1]; t[x].son[0]; x=t[x].son[0]);
Splay(x); int v1=t[y].val,v2=t[x].val;
if ((v2<<1)>v1) {
t[x].val=v1; t[y].val-=v2;
t[y].sum-=t[x].sum+v2; t[x].sum+=t[y].sum+v1-v2;
Access(x); Splay(y); t[y].son[0]=x; t[y].son[1]=0;
}
} //push x into y inline void DFS(int now,int last)
{
Add(now,last);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last)
DFS(edge[i].to,now);
} inline void Link(int x,int y)
{
int rx=Root(x),ry=Root(y);
ans-=t[rx].sum+t[ry].sum;
if (t[rx].val<t[ry].val) swap(x,y);
DFS(y,x); InsertEdge(x,y);
ans+=t[Root(x)].sum;
} } int main()
{ N=read(),M=read();
for (int i=1; i<=N; i++) LCT::t[i].val=LCT::t[i].size=1; while (M--) {
char opt[2]; scanf("%s",opt+1);
switch (opt[1]) {
int x,y;
case 'A' : x=read(),y=read(); LCT::Link(x,y); break;
case 'Q' : printf("%d\n",ans); break;
} } return 0;
}
【BZOJ-2888】资源运输 LCT + 启发式合并的更多相关文章
- BZOJ 2888 资源运输(启发式合并LCT)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2888 [题目大意] 不断加边,问每个连通块的重心到其它点的距离和的和 [题解] 启发式 ...
- [BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并
[BZOJ4530][Bjoi2014]大融合 试题描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是 ...
- BZOJ2888 资源运输(LCT启发式合并)
这道题目太神啦! 我们考虑他的每一次合并操作,为了维护两棵树合并后树的重心,我们只好一个一个的把节点加进去.那么这样一来看上去似乎就是一次操作O(nlogn),但是我们拥有数据结构的合并利器--启发式 ...
- BZOJ.3510.首都(LCT 启发式合并 树的重心)
题目链接 BZOJ 洛谷 详见这. 求所有点到某个点距离和最短,即求树的重心.考虑如何动态维护. 两棵子树合并后的重心一定在两棵树的重心之间那条链上,所以在合并的时候用启发式合并,每合并一个点检查sz ...
- 4.17 省选模拟赛 远行 LCT 启发式合并 倍增
容易写出nQ的暴力 由于数据是期望的时间 所以直接dfs可以跑的很快 可以拿到70分. 当然 可以进一步优化暴力 使用换根dp 然后可以将暴力优化到n^2. const int MAXN=300010 ...
- BZOJ 2809: [Apio2012]dispatching( 平衡树 + 启发式合并 )
枚举树上的每个结点做管理者, 贪心地取其子树中薪水较低的, 算出这个结点为管理者的满意度, 更新答案. 用平衡树+启发式合并, 时间复杂度为O(N log²N) ------------------- ...
- BZOJ 3545: [ONTAK2010]Peaks( BST + 启发式合并 + 并查集 )
这道题很好想, 离线, 按询问的x排序从小到大, 然后用并查集维护连通性, 用平衡树维护连通块的山的权值, 合并就用启发式合并.时间复杂度的话, 排序是O(mlogm + qlogq), 启发式合并是 ...
- BZOJ.4298.[ONTAK2015]Bajtocja(Hash 启发式合并)
题目链接 \(Description\) 给定\(d\)张无向图,每张图都有\(n\)个点.一开始,在任何一张图中都没有任何边. 接下来有\(m\)次操作,每次操作会给出\(a,b,k\),意为在第\ ...
- BZOJ 3545: [ONTAK2010]Peaks [Splay启发式合并]
3545: [ONTAK2010]Peaks 题意:带权图,多组询问与一个点通过边权\(\le x\)的边连通的点中点权k大值 又读错题了,输出点一直WA,问的是点权啊 本题加强版强制在线了,那这道题 ...
随机推荐
- github与gitlab与git三个基佬的故事
我们了解了git是以个人为中心,但是人人都得数据交互呀..python程序员每天都忙着进行py交易 交互数据的方式 使用github或者码云等公有代码仓库,托管代码的地方,谁都可以看 公司内部使用gi ...
- 贪心算法:Codevs 1044 拦截导弹
---恢复内容开始--- #include <iostream> #include <cstdio> #include <cstdlib> #include < ...
- J2EE规范 - 13种规范
J2EE是由SUN提出的用于简化开发企业级应用程序的一系列规范的组合,J2EE基于中间层集成的框架的方式为应用开发提供了一个统一的开发平台.基于容器管理.组件化的模型为企业建立一个高可用性,高可靠性可 ...
- AngularJS入门基础——表达式
表达式在AngularJS应用中广泛的使用,因此深入理解AngularJS如何使用并运算表达式是非常重要的. 表达式和eval非常相似,但是由于表达式由AngularJS来处理,它们有已下显著不同 ...
- [转]Centos 安装Sublime text 3
本文简单介绍在CentOS上安装Sublime text 3, 转自:Centos 安装Sublime text 3 Step 1 :建立软件安装目录 # mkdir /opt # cd /opt S ...
- TrID文件类型识别linux版
读取文件头根据特征码进行文件类型匹配. 官方:http://mark0.net/soft-trid-e.html windows版本小工具:FileAnalysis 以下是linux版本 wget h ...
- mybatis批量增加与删除——(十五)
1.首先应该明白,mybatis增删改返回值是int型的影响行数的值 mapper接口 package cn.xm.mapper; import java.util.List; import cn.x ...
- Servlet笔记8--乱码解决方案
乱码解决方案: 代码详解: package com.bjpowernode.javaweb.servlet; import java.io.IOException; import javax.serv ...
- 让linux中 history显示每条命令的操作时间及操作用户【转】
一.history 中显示日期时间用户名的办法 history 命令,用来显示命令行上的操作记录 不过默认是仅显示操作命令行本身,而没有记录操作时间等细节 例如 这样,我们查找记录时很麻烦,想回顾下某 ...
- Spring bean 配置
1.传统的创建对象的方式:JedisMall tardition=new JedisMall(); 这样是在程序运行时创建,表示当前模块已经不知不觉和new出的对象耦合了,而我们通常都是更高层次的抽象 ...