题解:

好题!!

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

调试时间长度应该也能上前五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. django前端到后端一次完整请求实例

    一.创建项目:# django-admin startproject mysite# cd mysite# python manage.py startapp blog 目录结构: 一.html文件: ...

  2. Django框架详解之views

    一个简单的视图 一个视图函数,是一个简单的python函数,它接受web请求并且返回web响应.无论视图本身包含什么逻辑,都要返回响应.为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为 ...

  3. Day 02 - 01 计算机的操作系统

    操作系统 场景:有以下三个人 1.庄园主 -->相当于人类 2.管家 --> 把人类要传达的信息分配给奴隶,相当于操作系统 3.奴隶 -->为人类干活的机器 1.操作系统做了什么? ...

  4. Win10内核驱动强制签名,申请沃通 EV代码签名证书

    2016年7月,微软在MSDN宣布从Windows 10的1607版本开始,强制要求所有新的Win10 内核驱动程序,必须获得Windows硬件开发者中心仪表盘门户的数字签名才能在系统中运行.这项政策 ...

  5. Flex tree展开节点问题!

    问题: 使用 for each(var item:XML in menuTree.dataProvider) {     menuTree.expandChildrenOf(item,true);   ...

  6. Vue学习之路第一篇(学习准备)

    1.开发工具的选择 这个和个人的开发习惯有关,并不做强求,厉害的话用记事本也可以.但是我还是建议用人气比较高的编辑工具,毕竟功能比较全面,开发起来效率比较高. 我之前写前端一直用的是sublimete ...

  7. CF449D Jzzhu and Numbers (状压DP+容斥)

    题目大意: 给出一个长度为n的序列,构造出一个序列使得它们的位与和为0,求方案数 也就是从序列里面选出一个非空子集使这些数按位与起来为0. 看了好久才明白题解在干嘛,我们先要表示出两两组合位与和为0的 ...

  8. 2019-03-18 OpenCV Tesseract-OCR 下载 安装 配置(cv2 报错)

    OpenCV 下载 安装 配置 1.下载和Python版本对应的版本,此为下载地址 2.安装(在powershell管理员模式下安装) pip3 install .\opencv_python-3.4 ...

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

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

  10. jvm 虚拟机参数_栈内存分配

    1.参数 -Xss 指定线程最大的栈空间,整个参数也直接决定了函数可调用的最大深度 2.测试代码 private static int count; public static void addCou ...