题解:

好题!!

这题似乎能上我代码长度记录的前五?

调试时间长度应该也能上前五QAQ

首先题目要求的明显就是最小割,当然在整个森林上求Q次最小割肯定是会GG的,所以我们需要一个能快速求最小割的算法——最小割树。

最小割树,也叫分治最小割,就是通过预处理把原本的图缩成一颗树,树上两个节点路径上的最小边权就是它们的最小割,这个用树上倍增可以随便维护。

大概思想就是先求一次最小割,把划分出的S和T两个点集继续求最小割,向下分治然后连边缩点。

这题先对每个州预处理最小割树,州和州之间用KD树求出距离最近的点,然后查询的时候用树上倍增跳。

分别写出来就好了qwq

所以这就是道码农题,码码码码码码

有必要说一下时间复杂度是O(玄学),这个时间复杂度严格来说是过不了的,但是数据随机,每个州和大的森林联通块的期望大小不大,所以不知道为什么就过了。。。

PS:我没写KD树,写了个排序剪枝,也是玄学就过了。。。

代码:

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#define inf 2147483647
#define eps 1e-9
using namespace std;
typedef long long ll;
struct node{
int x,y,id;
friend bool operator <(node a,node b){
if(a.x!=b.x)return a.x<b.x;
if(a.y!=b.y)return a.y<b.y;
return a.id<b.id;
}
}p[],pp[];
int N,n,m,q,u,v,w,ta,tb,qa,qb,cnt=,bcc=,num[],fr[],pts[],blg[];
bool used[];
namespace capitals{
struct edge{
int v,w,next;
}a[];
int tot=,head[],dep[],fa[][],minn[][];
void add(int u,int v,int w){
a[++tot].v=v;
a[tot].w=w;
a[tot].next=head[u];
head[u]=tot;
}
void dfs(int u,int ff,int dpt,int d){
blg[u]=bcc;
dep[u]=dpt;
fa[u][]=ff;
minn[u][]=d;
for(int i=;i<=;i++){
fa[u][i]=fa[fa[u][i-]][i-];
minn[u][i]=min(minn[u][i-],minn[fa[u][i-]][i-]);
}
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(v!=ff){
dfs(v,u,dpt+,a[tmp].w);
}
}
}
int query(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int ret=inf;
for(int i=;i>=;i--){
if(dep[fa[u][i]]>=dep[v]){
ret=min(ret,minn[u][i]);
u=fa[u][i];
}
}
if(u==v)return ret;
for(int i=;i>=;i--){
if(fa[u][i]!=fa[v][i]){
ret=min(ret,min(minn[u][i],minn[v][i]));
u=fa[u][i],v=fa[v][i];
}
}
return min(ret,min(minn[u][],minn[v][]));
}
}
namespace dinic{
struct edge{
int v,w,next;
}a[];
int n,m,vs,vt,tot=,dep[],s[],flw[],nmd[],head[];
queue<int>q;
void add(int u,int v,int w){
a[++tot].v=v;
a[tot].w=w;
a[tot].next=head[u];
head[u]=tot;
}
void clr(){
//memset(head,-1,sizeof(head));
for(int i=;i<=n;i++)head[i]=-;
tot=;
}
bool bfs(){
for(int i=;i<=n;i++)dep[i]=;
while(!q.empty())q.pop();
q.push(vs);
dep[vs]=;
while(!q.empty()){
int u=q.front();
q.pop();
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(!dep[v]&&a[tmp].w){
dep[v]=dep[u]+;
if(v==vt)return true;
q.push(v);
}
}
}
return false;
}
int dfs(int u,int num){
if(u==vt||!num)return num;
int ans=;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(dep[v]==dep[u]+&&a[tmp].w){
int f=dfs(v,min(num,a[tmp].w));
if(f){
a[tmp].w-=f;
a[tmp^].w+=f;
ans+=f;
num-=f;
if(!num)break;
}
}
}
if(!ans)dep[u]=-;
return ans;
}
void build_mincost(int l,int r){
if(r<=l)return;
int dnc=,ls=l,rs=r;
vs=nmd[l],vt=nmd[r];
for(int i=;i<=tot+;i++)a[i].w=flw[i/];
while(bfs())dnc+=dfs(vs,inf);
for(int i=l;i<=r;i++){
if(dep[nmd[i]])s[ls++]=nmd[i];
else s[rs--]=nmd[i];
}
for(int i=l;i<=r;i++)nmd[i]=s[i];
capitals::add(vs+cnt,vt+cnt,dnc);
capitals::add(vt+cnt,vs+cnt,dnc);
//printf("Added %d->%d Flow=%d\n",vs+cnt,vt+cnt,dnc);
build_mincost(l,ls-);
build_mincost(rs+,r);
}
}
int dis(node a,node b){
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
void solve(int k){
int ans=inf,now=;
for(int i=k+;i<=N;i++){
if((pp[i].x-pp[k].x)*(pp[i].x-pp[k].x)>ans)break;
int ds=dis(pp[i],pp[k]);
if(ds<ans){
ans=ds;
now=i;
}else if(ds==ans&&pp[i].id<pp[now].id)now=i;
}
for(int i=k-;i;i--){
if((pp[i].x-pp[k].x)*(pp[i].x-pp[k].x)>ans)break;
int ds=dis(pp[i],pp[k]);
if(ds<ans){
ans=ds;
now=i;
}else if(ds==ans&&pp[i].id<pp[now].id)now=i;;
}
fr[pp[k].id]=pp[now].id;
}
int main(){
memset(capitals::head,-,sizeof(capitals::head));
scanf("%d",&N);
for(int i=;i<=N;i++){
scanf("%d%d%d%d%d",&p[i].x,&p[i].y,&num[i],&n,&m);
p[i].id=i;
pp[i]=p[i];
pts[i]=cnt+;
dinic::n=n;
dinic::m=m;
dinic::clr();
for(int j=;j<=n;j++)dinic::nmd[j]=j;
for(int j=;j<=m;j++){
scanf("%d%d%d",&u,&v,&w);
dinic::add(u,v,w);
dinic::add(v,u,w);
dinic::flw[j]=w;
}
dinic::build_mincost(,n);
cnt+=n;
}
sort(pp+,pp+N+);
for(int i=;i<=N;i++)solve(i);
for(int i=;i<=N;i++){
if(used[i])continue;
if(i==fr[fr[i]]){
used[fr[i]]=true;
capitals::add(pts[i],pts[fr[i]],num[i]+num[fr[i]]);
capitals::add(pts[fr[i]],pts[i],num[i]+num[fr[i]]);
//printf("Added %d->%d Flow=%d\n",pts[fr[i]],pts[i],num[i]+num[fr[i]]);
}else{
capitals::add(pts[i],pts[fr[i]],num[i]);
capitals::add(pts[fr[i]],pts[i],num[i]);
//printf("Added %d->%d Flow=%d\n",pts[fr[i]],pts[i],num[i]);
}
}
for(int i=;i<=N;i++){
if(!blg[pts[i]]){
bcc++;
capitals::dfs(pts[i],,,inf);
}
}
scanf("%d",&q);
for(int i=;i<=q;i++){
scanf("%d%d%d%d",&ta,&tb,&qa,&qb);
qa=pts[ta]+qa-;
qb=pts[tb]+qb-;
if(blg[qa]!=blg[qb])puts("");
else printf("%d\n",capitals::query(qa,qb));
}
return ;
}

(2016北京集训十三)【xsy1532】网络战争 - 最小割树+树上倍增+KD树的更多相关文章

  1. [2016北京集训试题6]网络战争-[最小割树(网络流)+kd-tree+倍增]

    Description A 联邦国有 N 个州,每个州内部都有一个网络系统,有若干条网络线路,连接各个 州内部的城市. 由于 A 国的州与州之间的关系不是太好,每个州都只有首府建立了到别的州的网络.具 ...

  2. (2016北京集训十三)【xsy1531】魔法游戏 - Nim游戏

    题解: 好题!我的结论很接近正解了... 把一个数化成二进制,每次至少要拿走一位,最多全拿走,不能不拿.那么这就是一个经典的Nim问题了,子树异或起来就是根节点的答案,随便递推一下就行了. 代码: # ...

  3. (2016北京集训十三)【xsy1533】mushroom - bitset

    题解: 神题...我看到的时候直接吓懵了... 这是一道STL题...否则可能要写可持久化ETT或者可持久化Toptree? 用bitset来维护每个蘑菇上哪里有杂草,那么 对于操作1和操作2:可以预 ...

  4. 2016北京集训测试赛(十三) Problem B: 网络战争

    Solution KD tree + 最小割树

  5. (2016北京集训十)【xsy1528】azelso - 概率期望dp

    北京集训的题都是好题啊~~(于是我爆0了) 注意到一个重要的性质就是期望是线性的,也就是说每一段的期望步数可以直接加起来,那么dp求出每一段的期望就行了... 设$f_i$表示从$i$出发不回到$i$ ...

  6. 2016北京集训测试赛(六)Problem B: 矩阵

    Solution 最小割. 参考BZOJ 3144切糕 在那道题的基础上将建图方法稍作变形: 我们对格子进行黑白染色, 对于两个格子之和\(\le k\)的限制, 就可以确定其中一个是白色格子, 一个 ...

  7. LOJ6045 雅礼集训 2017 Day8 价(最小割)

    由Hall定理,任意k种减肥药对应的药材数量>=k.考虑如何限制其恰好为k,可以将其看作是使对应的药材数量尽量少. 考虑最小割.建一个二分图,左边的点表示减肥药,右边的点表示药材.减肥药和其使用 ...

  8. [NOIP2013/Codevs3287]货车运输-最小[大]生成树-树上倍增

    Problem 树上倍增 题目大意 给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大. Solution 看到这个题第一反应是图论.. 然而,任意路径最小的边权值最大,如 ...

  9. 【2016北京集训】Mushroom

    Portal --> broken qwq Description 一开始有个蘑菇,蘑菇里面有\(n\)个房间,是一棵有根树,\(1\)号是根,每个房间里面都有杂草,现在要支持以下操作:将某个指 ...

随机推荐

  1. Unity中 Animator 与Animation 区别

    ①Animation和Animator 虽然都是控制动画的播放,但是它们的用法和相关语法都是大有不同的.Animation 控制一个动画的播放,而Animator是多个动画之间相互切换,并且Anima ...

  2. java导出excel通用方法

    首先需要引入的jar包: 正式代码了. import java.io.FileOutputStream; import java.io.OutputStream; import java.net.UR ...

  3. LeetCode Golang 7. 整数反转

    7. 整数反转 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. Tips : Math包给出的类型大小的边界: // Integer limit values. const ...

  4. Is jQuery Still Relevant in 2018?

    DOM Selection $('.someclass') document.querySelector('.someclass') document.querySlectorAll('.somecl ...

  5. 代理上网环境配置docker私有库

    最后更新时间:2018年12月27日 Docker使用代理上网去 pull 各类 images,需要做如下配置: 创建目录: /etc/systemd/system/docker.service.d ...

  6. [转载] Linux新手必看:浅谈如何学习linux

    本文转自 https://www.cnblogs.com/evilqliang/p/6247496.html 本文在Creative Commons许可证下发布 一.起步 首先,应该为自己创造一个学习 ...

  7. Django REST Framework 数码宝贝 - 3步进化 - 混合类 -->

    读了我这篇博客, 你会刷新对面对对象的认知, 之前的面对对象都是LJ~~~ 表结构 class Publisher(models.Model): name = models.CharField(max ...

  8. windows服务器剪贴板不能共用的解决办法

    远程桌面无法使用剪贴板共享纯文本的解决方法========================================以下操作须在远程桌面上操作,本地机没用的!================== ...

  9. 华硕VX50V开机老是进入bios

    问题:华硕VX50V开机老是进入bios 如图: 解决办法: 1.将   Boot  中的--->>  Lunch CSM  ---->>设置为  -->> ena ...

  10. ASP.NET-表单验证-DataAnnotations

    DataAnnotations  [数据注解,数据注释] 需要引入两个脚本文件 <script src="@Url.Content("~/Scripts/jquery.val ...