【XSY2771】城市 分治
题目描述
一个平原上有\(n\)个城市,第\(i\)个城市在点\((\cos \frac{2i\pi}{n},\sin \frac{2i\pi}{n})\)上。
每个城市和最近的两个城市有一条直线段的路。
此外,还有\(n-3\)条路,这些路不会和原有的路重合,这些路之间也不会相交。
通过每条道路均要花费\(1\)的时间。
每次给你两个城市,问你从一个城市到另一个城市最快要多久。
\(n\leq 100000\)
题解
先把图画出来,容易发现这是一个平面图,且这个图的对偶图是一棵树,每个点的度数不超过\(3\)。
那么我们可以对这棵树分治(点分治边分治都可以)。
每次选择一条边,对于每个询问,这个询问的最短路径可以经过这条边的两个端点,也可以不经过。
那么可以从这条边的两个端点开始BFS,并更新答案。
对于一个询问,如果这个询问的两个点不在这条边的同一侧,就可以把这个询问扔掉了,否则递归下去处理。
时间复杂度:\(O(n\log n)\)
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<utility>
#include<vector>
#include<queue>
using namespace std;typedef long long ll;typedef pair<int,int> pii;void open(const char *s){
#ifndef ONLINE_JUDGE
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}int rd(){int s,c;while((c=getchar())<'0'||c>'9');s=c-'0';while((c=getchar())>='0'&&c<='9')s=s*10+c-'0';return s;}
vector<int> g[100010];
int e[100010][3];
int qu[100010][3];
int c[100010];
int ti;
int tot;
int b[100010];
queue<int> q;
int num[100010];
int ans[100010];
int d[100010];
void bfs(int x)
{
d[x]=0;
q.push(x);
ti++;
b[x]=ti;
while(!q.empty())
{
x=q.front();
q.pop();
for(auto v:g[x])
if(c[v]==tot&&b[v]!=ti)
{
d[v]=d[x]+1;
b[v]=ti;
q.push(v);
}
}
}
int cnt;
int dist(int l,int r)
{
if(r<l)
r+=cnt;
return r-l+1;
}
int belong(int l,int r,int x)
{
if(l>r)
r+=cnt;
if(x<l)
x+=cnt;
return x<=r;
}
int belong2(int l,int r,int x)
{
if(l>r)
r+=cnt;
if(x<=l)
x+=cnt;
return x<r;
}
void solve(vector<int> &id,vector<int> &qid)
{
if(!qid.size())
return;
if(id.size()<=1)
return;
tot++;
cnt=0;
for(auto v:id)
{
c[v]=tot;
num[v]=++cnt;
}
int s=0x7fffffff,x1,x2;
for(auto v1:id)
for(auto v2:g[v1])
if(c[v2]==tot)
{
int v=max(dist(num[v1],num[v2]),dist(num[v2],num[v1]));
if(v<s)
{
s=v;
x1=v1;
x2=v2;
}
}
bfs(x1);
for(auto v:qid)
ans[v]=min(ans[v],d[qu[v][1]]+d[qu[v][2]]);
bfs(x2);
for(auto v:qid)
ans[v]=min(ans[v],d[qu[v][1]]+d[qu[v][2]]);
if(id.size()<=3)
return;
vector<int> id1,id2,qid1,qid2;
for(auto v:id)
{
if(belong(num[x1],num[x2],num[v]))
id1.push_back(v);
if(belong(num[x2],num[x1],num[v]))
id2.push_back(v);
}
for(auto v:qid)
{
if(belong2(num[x1],num[x2],num[qu[v][1]])&&belong2(num[x1],num[x2],num[qu[v][2]]))
qid1.push_back(v);
if(belong2(num[x2],num[x1],num[qu[v][1]])&&belong2(num[x2],num[x1],num[qu[v][2]]))
qid2.push_back(v);
}
solve(id1,qid1);
solve(id2,qid2);
}
int n,m;
int main()
{
open("b");
scanf("%d",&n);
int x,y;
for(int i=1;i<=n-3;i++)
{
scanf("%d%d",&x,&y);
x++;
y++;
g[x].push_back(y);
g[y].push_back(x);
e[i][1]=x;
e[i][2]=y;
}
for(int i=1;i<=n;i++)
{
g[i].push_back(i%n+1);
g[i%n+1].push_back(i);
}
vector<int> id,qid;
for(int i=1;i<=n;i++)
id.push_back(i);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&qu[i][1],&qu[i][2]);
qu[i][1]++;
qu[i][2]++;
qid.push_back(i);
if(qu[i][1]==qu[i][2])
ans[i]=0;
else
ans[i]=0x7fffffff;
}
solve(id,qid);
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
【XSY2771】城市 分治的更多相关文章
- 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)
[BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...
- BZOJ2001 [Hnoi2010]City 城市建设 CDQ分治
2001: [Hnoi2010]City 城市建设 Time Limit: 20 Sec Memory Limit: 162 MB Description PS国是一个拥有诸多城市的大国,国王Lou ...
- 【HNOI2010】城市建设(对时间分治 & Kruskal)
Description \(n\) 个点 \(m\) 条边的带边权无向图.\(q\) 次操作,每次修改一条边的权值. 求每次修改后的最小生成树的边权和. Hint \(1\le n\le 2\time ...
- BZOJ2001 HNOI2010城市建设(线段树分治+LCT)
一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST.理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗.正解写不动了. #include<iostream> ...
- 【CDQ分治】[HNOI2010]城市建设
题目链接 线段树分治+LCT只有80 然后就有了CDQ分治的做法 把不可能在生成树里的扔到后面 把一定在生成树里的扔到并查集里存起来 分治到l=r,修改边权,跑个kruskal就行了 由于要支持撤销, ...
- BZOJ2001 [Hnoi2010]City 城市建设 【CDQ分治 + kruskal】
题目链接 BZOJ2001 题解 CDQ分治神题... 难想难写.. 比较朴素的思想是对于每个询问都求一遍\(BST\),这样做显然会爆 考虑一下时间都浪费在了什么地方 我们每次求\(BST\)实际上 ...
- bzoj 2001 CITY 城市建设 cdq分治
题目传送门 题解: 对整个修改的区间进行分治.对于当前修改区间来说,我们对整幅图中将要修改的边权都先改成-inf,跑一遍最小生成树,然后对于一条树边并且他的权值不为-inf,那么这条边一定就是树边了. ...
- P3206 [HNOI2010]城市建设 [线段树分治+LCT维护动态MST]
Problem 这题呢 就边权会在某一时刻变掉-众所周知LCT不支持删边的qwq- 所以考虑线段树分治- 直接码一发 如果 R+1 这个时间修改 那就当做 [L,R] 插入了一条边- 然后删的边和加的 ...
- BZOJ 2001: [Hnoi2010]City 城市建设
2001: [Hnoi2010]City 城市建设 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1132 Solved: 555[Submit][ ...
随机推荐
- H3C交换机-SNMP配置
1.1 SNMP基础配置 1.启动/关闭SNMP Agent服务 在系统视图模式下: 启用:snmp-agent 关闭:undo snmp-agent 注:缺省情况下snmp agent是关闭 ...
- kattis Programming Tutors 给游客与导游匹配(二分+二分图)
题目来源:https://vjudge.net/problem/Kattis-programmingtutors 题意: 有n个游客,n个导游,给出他们的坐标,问你怎么匹配可以使他们最大距离最小 题解 ...
- ARC 066D Xor Sum AtCoder - 2272 (打表找规律)
Problem Statement You are given a positive integer N. Find the number of the pairs of integers u and ...
- Mysql数据库中索引的概念总结
1.索引的目的是什么 1.快速访问数据表中的特定信息,提高检索速度 2.创建唯一性索引,保证数据库表中每一行数据的唯一性. 3.加速表和表之间的连接 4.使用分组和排序子句进行数据检索时,可以显著减少 ...
- 通过C#调用,实现js加密代码的反混淆,并运行js函数
前一篇我测试了vba调用htmlfile做反混淆,并执行js加密函数的代码.本文换成C#实现. 联系QQ:564955427 C#操作JS函数,可以通过ScriptControl组件,但这个组件只能在 ...
- 练习MD5加密jar包编写
简介 参数签名可以保证开发的者的信息被冒用后,信息不会被泄露和受损.原因在于接入者和提供者都会对每一次的接口访问进行签名和验证. 签名sign的方式是目前比较常用的方式. 第1步:接入者把需求访问的接 ...
- Oracle SQL优化原则
原文:http://bbs.landingbj.com/t-0-240353-1.html 1.选用适合的 ORACLE 优化器 2.访问 Table 的方式 3.共享SQL语句 共享的语句必须满足三 ...
- PMP三点
三点估算:悲观36天,可能21天,乐观6天.在16至26天内完成的概率是多少?这个算法是PERT估算最终估算结果=(悲观工期+乐观工期+4×最可能工期)/6=(36+6++4*21)/6=21标准差= ...
- 剑指offer(1)
题目: 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. ...
- Python基础知识2-内置数据结构(上)
分类 数值型 用浮点型的时候注意别和"=="一起使用. 数字的处理函数 注意round()函数的特殊:四舍六入五取偶 类型判断 列表list 列表list定义 初始化 列表索引访 ...