Gym 100851 Distance on Triangulation
题意:给你一个N边形, 然后这个n边形有n-3条边,然后询问2点之间的最短路。
题解:分治。
我们可以找到一条边,使得这幅图能分成大小相同的2幅图,那么我们就可以确定那些被分割开的询问的答案是多少了。
我们假定u v是分开的, 然后我们从u点bfs一遍现在的图,v点bfs一遍现在的图,确定所有点离这2个点的位置,对于切断的询问更新答案。
需要注意的就是,每次都一定要重新建图,免得遍历太多的没有用的边。
递归结束的时候是这幅图只有3个点了,如果在3个点中的最短路,那么一定是1,假定2点不重合。
代码1:离线写法
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("distance.in","r",stdin); freopen("distance.out","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
struct Node{
int u, v, id;
};
vector<int> vc[N][], ee[N];
vector<pll> e[N][];
vector<Node> q[N][];
int ans[N], pos[N], num[N];
int lf[N], rt[N], ok[N];
int d[N][];
queue<int> que;
void bfs(int b, int id){
d[b][id] = ;
que.push(b);
while(!que.empty()){
int u = que.front();
que.pop();
for(auto v : ee[u]){
if(d[v][id] > d[u][id]+){
d[v][id] = d[u][id]+;
que.push(v);
}
}
}
}
void solve(int k, int op){
if(vc[k][op].size() <= || q[k][op].size() == ) return ;
int nodes = vc[k][op].size();
for(int i = ; i < nodes; ++i){
ee[i].clear();
pos[vc[k][op][i]] = i;
d[i][] = d[i][] = inf;
ee[i].pb((i+)%nodes);
ee[i].pb((i-+nodes)%nodes);
}
int Max = inf, id = ;
for(int i = ; i < e[k][op].size(); ++i){
int u = e[k][op][i].fi, v = e[k][op][i].se;
int tmp = max(pos[v]-pos[u], nodes - pos[v]+pos[u]);
if(tmp < Max) {
Max = tmp;
id = i;
}
ee[pos[u]].pb( pos[v]);
ee[pos[v]].pb( pos[u]);
}
vc[k+][].clear(); vc[k+][].clear();
q[k+][].clear(); q[k+][].clear();
e[k+][].clear(); e[k+][].clear();
int tu = e[k][op][id].fi, tv = e[k][op][id].se;
for(int i = ; i < nodes; ++i){
if(vc[k][op][i] == tu || vc[k][op][i] == tv){
vc[k+][].pb(vc[k][op][i]);
vc[k+][].pb(vc[k][op][i]);
}
else if(vc[k][op][i] < tu || vc[k][op][i] > tv)
vc[k+][].pb(vc[k][op][i]), lf[vc[k][op][i]] = ;
else
vc[k+][].pb(vc[k][op][i]), rt[vc[k][op][i]] = ;
}
bfs(pos[tu], );
bfs(pos[tv], );
for(int i = , u, v; i < e[k][op].size(); ++i){
u = e[k][op][i].fi, v = e[k][op][i].se;
if(lf[u] || lf[v]) e[k+][].pb(e[k][op][i]);
else if(rt[u] || rt[v]) e[k+][].pb(e[k][op][i]);
}
for(int i = , u, v, aid; i < q[k][op].size(); ++i){
u = q[k][op][i].u, v = q[k][op][i].v, aid = q[k][op][i].id;
if(lf[u] && lf[v]) {
q[k+][].pb(q[k][op][i]);
continue;
}
else if(rt[u] && rt[v]){
q[k+][].pb(q[k][op][i]);
continue;
}
u = pos[u], v = pos[v];
ans[aid] = min(d[u][]+d[v][], d[u][] + d[v][]);
}
for(auto v : vc[k][op]){
lf[v] = rt[v] = ;
ok[v] = ;
}
solve(k+, );
solve(k+, );
}
int main(){
Fopen;
int n, m, u, v;
scanf("%d", &n);
for(int i = ; i <= n; ++i){
vc[][].pb(i);
}
for(int i = ; i <= n - ; ++i){
scanf("%d%d", &u, &v);
if(u > v) swap(u,v);
e[][].pb({u,v});
}
scanf("%d", &m);
for(int i = ; i <= m; ++i){
scanf("%d%d", &u, &v);
if(u > v) swap(u,v);
if(u == v)
continue;
q[][].pb({u,v,i});
}
solve(,);
for(int i = ; i <= m; ++i){
printf("%d\n", ans[i]);
}
return ;
}
离线看着麻烦 其实还是挺简单的。
代码2:在线写法
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("distance.in","r",stdin); freopen("distance.out","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 5e4+;
vector<int> ee[N];
int pos[N], que[N];
struct Node{
vector<int> v, d[];
vector<pll> e;
int mn, mx, nodes;
Node * lson, * rson;
void bfs(int b,int id){
d[id][b] = ;
int l = , r = ;
que[l] = b;
while(l < r){
int u = que[l++];
for(auto v : ee[u]){
if(d[id][v] > d[id][u]+){
d[id][v] = d[id][u]+;
que[r++] = v;
}
}
}
}
void solve(){
nodes = v.size();
if(nodes <= ) return ;
for(int i = ; i < nodes; ++i){
pos[v[i]] = i;
d[].pb(inf); d[].pb(inf);
ee[i].clear();
ee[i].pb((i+)%nodes);
ee[i].pb((i+nodes-)%nodes);
}
int Max = inf, id = ;
for(int i = ; i < nodes-; ++i){\
int x = pos[e[i].fi], y = pos[e[i].se];
int tmp = max(y-x, nodes-(y-x));
if(tmp < Max) {
Max = tmp;
id = i;
}
ee[x].pb(y);
ee[y].pb(x);
}
mn = e[id].fi, mx = e[id].se;
lson = new Node; rson = new Node;
for(int i = ; i < nodes; ++i){
if(v[i] >= mn && v[i] <= mx) lson -> v.pb(v[i]);
if(v[i] <= mn || v[i] >= mx) rson -> v.pb(v[i]);
}
bfs(pos[mn], );
bfs(pos[mx], );
for(int i = ; i < nodes-; ++i){
int x = e[i].fi, y = e[i].se;
if((x > mn && x < mx) || (y > mn && y < mx)) lson -> e.pb(e[i]);
if(x < mn || y < mn || x > mx || y > mx) rson -> e.pb(e[i]);
}
lson -> solve();
rson -> solve();
}
int Query(int x, int y){
if(nodes <= ) return ;
if((x > mn && x < mx) && (y > mn && y < mx)) return lson -> Query(x,y);
if((x < mn || x > mx) && (y < mn || y > mx)) return rson -> Query(x,y);
x = lower_bound(v.begin(), v.end(), x) - v.begin();
y = lower_bound(v.begin(), v.end(), y) - v.begin();
return min(d[][x]+d[][y], d[][x]+d[][y]);
}
}rt; int main(){
Fopen;
int n, m, u, v;
scanf("%d", &n);
for(int i = ; i <= n; ++i){
rt.v.pb(i);
}
for(int i = ; i <= n - ; ++i){
scanf("%d%d", &u, &v);
if(u > v) swap(u,v);
rt.e.pb({u,v});
}
rt.solve();
scanf("%d", &m);
while(m--){
scanf("%d%d", &u, &v);
int ans = ;
if(u != v) ans = rt.Query(u,v);
printf("%d\n", ans);
}
return ;
}
在线写法要确定询问的点是不是都在一副新的图上,是就继续往下递归,否就在这个地方询问。
这题目中在线比离线的慢一点点。
因为在线写法的询问是严格的lg(n)是一个固定值,因为每次往下走,你就会使得二分的长度/2,就相当于是二分了一次了。。。。。
然后我又写了一个bug,疯狂TLE,惊了。
int Max = inf, id = ;
for(int i = ; i < e[k][op].size(); ++i){
int u = e[k][op][i].fi, v = e[k][op][i].se;
int tmp = max(pos[v]-pos[u], nodes - pos[v]+pos[u]);
if(tmp < Max) {
tmp = Max;
id = i;
}
ee[pos[u]].pb( pos[v]);
ee[pos[v]].pb( pos[u]);
}
看着没什么问题。。。实际上问题大了。
应该是 Max = tmp。。。 这样加多了递归的层数,然后会加多存的东西,会导致TLE和MLE。
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("distance.in","r",stdin); freopen("distance.out","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
struct Node{
int u, v, id;
};
vector<int> vc[N][], ee[N];
vector<pll> e[N][];
vector<Node> q[N][];
int ans[N], pos[N], num[N];
int lf[N], rt[N], ok[N];
int d[N][];
queue<int> que;
void bfs(int b, int id){
d[b][id] = ;
que.push(b);
while(!que.empty()){
int u = que.front();
que.pop();
for(auto v : ee[u]){
if(ok[v] && d[v][id] > d[u][id]+){
d[v][id] = d[u][id]+;
que.push(v);
}
}
}
}
void solve(int k, int op){
if(vc[k][op].size() <= || q[k][op].size() == ) return ;
for(int i = ; i < vc[k][op].size(); ++i){
pos[vc[k][op][i]] = i;
d[vc[k][op][i]][] = d[vc[k][op][i]][] = inf;
ok[vc[k][op][i]] = ;
}
int Max = inf, id = , totnum = vc[k][op].size();
for(int i = ; i < e[k][op].size(); ++i){
int u = e[k][op][i].fi, v = e[k][op][i].se;
int tmp = max(pos[v]-pos[u]-, totnum - (pos[v]-pos[u]-) - );
if(tmp < Max) {
tmp = Max;
id = i;
}
}
vc[k+][].clear(); vc[k+][].clear();
vc[k+][].shrink_to_fit(); vc[k+][].shrink_to_fit();
q[k+][].clear(); q[k+][].clear();
q[k+][].shrink_to_fit(); q[k+][].shrink_to_fit();
e[k+][].clear();e[k+][].clear();
e[k+][].shrink_to_fit(); e[k+][].shrink_to_fit();
int tu = e[k][op][id].fi, tv = e[k][op][id].se;
for(int i = ; i < totnum; ++i){
if(vc[k][op][i] == tu || vc[k][op][i] == tv){
vc[k+][].pb(vc[k][op][i]);
vc[k+][].pb(vc[k][op][i]);
}
else if(vc[k][op][i] < tu || vc[k][op][i] > tv)
vc[k+][].pb(vc[k][op][i]), lf[vc[k][op][i]] = ;
else
vc[k+][].pb(vc[k][op][i]), rt[vc[k][op][i]] = ;
}
bfs(tu,);
bfs(tv,);
for(int i = , u, v; i < e[k][op].size(); ++i){
u = e[k][op][i].fi, v = e[k][op][i].se;
if(lf[u] || lf[v]) e[k+][].pb(e[k][op][i]);
else if(rt[u] || rt[v]) e[k+][].pb(e[k][op][i]);
}
for(int i = , u, v, aid; i < q[k][op].size(); ++i){
u = q[k][op][i].u, v = q[k][op][i].v, aid = q[k][op][i].id;
if(lf[u] && lf[v]) {
q[k+][].pb(q[k][op][i]);
continue;
}
else if(rt[u] && rt[v]){
q[k+][].pb(q[k][op][i]);
continue;
}
ans[aid] = min(ans[aid], d[u][]+d[v][]);
ans[aid] = min(ans[aid], d[u][]+d[v][]);
}
for(auto v : vc[k][op]){
lf[v] = rt[v] = ;
ok[v] = ;
}
vc[k][op].clear();
vc[k][op].shrink_to_fit();
e[k][op].clear();
e[k][op].shrink_to_fit();
q[k][op].clear();
q[k][op].shrink_to_fit();
solve(k+, );
solve(k+, );
}
int main(){
Fopen;
int n, m, u, v;
scanf("%d", &n);
for(int i = ; i < n; ++i){
vc[][].pb(i);
ee[i].pb(i+);
ee[i+].pb(i);
}
vc[][].pb(n);
ee[].pb(n); ee[n].pb();
for(int i = ; i <= n - ; ++i){
scanf("%d%d", &u, &v);
if(u > v) swap(u,v);
e[][].pb({u,v});
ee[u].pb(v);
ee[v].pb(u);
}
scanf("%d", &m);
memset(ans, inf, sizeof ans);
for(int i = ; i <= m; ++i){
scanf("%d%d", &u, &v);
if(u > v) swap(u,v);
if(u == v) {
ans[i] = ;
continue;
}
q[][].pb({u,v,i});
}
solve(,);
for(int i = ; i <= m; ++i){
printf("%d\n", ans[i]);
}
return ;
}
然后顶着这个破代码 各种乱写 各种MLE, 然后把每一层的东西不需要的那时候马上clear 和 清除空间, 然后就过了。
然后想改成在线的,改了半天改不动才发现了上面的那个问题。
Gym 100851 Distance on Triangulation的更多相关文章
- 【二分】NEERC15 L Landscape Improved(2015-2016 ACM-ICPC)(Codeforces GYM 100851)
		
题目链接: http://codeforces.com/gym/100851 题目大意: 一个宽度为N的网格图,i上有h[i]高的方块.现在你有W个方块,问怎么放使得最终的最高点最高. 只要一个格子的 ...
 - 【模拟】NEERC15 G Generators(2015-2016 ACM-ICPC)(Codeforces GYM 100851)
		
题目链接: http://codeforces.com/gym/100851 题目大意: n个序列.每个序列有4个值x,a,b,c,之后按照x=(a*x+b)%c扩展无穷项. 求每个序列各取一个数之后 ...
 - 【模拟】NEERC15 J Jump(2015-2016 ACM-ICPC)(Codeforces GYM 100851)
		
题目链接: http://codeforces.com/gym/100851 题目大意: 系统里生成一个字符串C,一开始告诉你字符串的长度N(偶数).接着你需要在n+500次内猜出这个字符串是什么. ...
 - 【最短路】NEERC15 F Froggy Ford(2015-2016 ACM-ICPC)(Codeforces GYM 100851)
		
题目链接: http://codeforces.com/gym/100851 题目大意: 一只青蛙跳过宽为W的河,河中游N个石头,坐标xi,yi,现在往河中间添加一个石头,使得每次跳跃的最大的距离最小 ...
 - 【模拟】NEERC15 E Easy Problemset (2015-2016 ACM-ICPC)(Codeforces GYM 100851)
		
题目链接: http://codeforces.com/gym/100851 题目大意: N个人,每个人有pi个物品,每个物品价值为0~49.每次从1~n顺序选当前这个人的物品,如果这个物品的价值&g ...
 - 【模拟】NEERC15 A Adjustment Office (2015-2016 ACM-ICPC)(Codeforces GYM 100851)
		
题目链接: http://codeforces.com/gym/100851 题目大意: 一个N*N的矩阵A,Ai,j=i+j,Q次操作,每次分两种,R r取出第r行还未被取的所有数,并输出和.C c ...
 - BZOJ4449 : [Neerc2015]Distance on Triangulation
		
首先拓扑,每次取出度数为$2$的点,这样可以把所有三角形都找到. 那么建出对偶图,会发现是一棵树. 对这棵树进行点分治,每次取出重心,DFS求出所有在里面的点,然后从重心$3$个点分别做一次BFS. ...
 - 【bzoj 4449】[Neerc2015]Distance on Triangulation
		
Description 给定一个凸n边形,以及它的三角剖分.再给定q个询问,每个询问是一对凸多边行上的顶点(a,b),问点a最少经过多少条边(可以是多边形上的边,也可以是剖分上的边)可以到达点b. I ...
 - bzoj 4449: [Neerc2015]Distance on Triangulation
		
Description 给定一个凸n边形,以及它的三角剖分.再给定q个询问,每个询问是一对凸多边行上的顶点(a,b),问点a最少经过多少条边(可以是多边形上的边,也可以是剖分上的边)可以到达点b. I ...
 
随机推荐
- 二、Markdown基本语法
			
目录 2.1 标题 一级标题 二级标题 三级标题 2.2 加粗 2.3倾斜 2.4 高亮 2.5 上标 2.6 下标 2.7 代码引用(>式) 2.8 代码引用(```式) 2.9 代码引入(` ...
 - 【POJ - 3104 】Drying(二分)
			
Drying 直接上中文 Descriptions 每件衣服都有一定单位水分,在不使用烘干器的情况下,每件衣服每分钟自然流失1个单位水分,但如果使用了烘干机则每分钟流失K个单位水分,但是遗憾是只有1台 ...
 - Wpf窗口设置可拖动
			
在窗口界面的一个控件(TopGrid)设置如下MouseLeftButtonDown事件即可 private void TopGrid_MouseLeftButtonDown(object sende ...
 - 分布式ID系列(2)——UUID适合做分布式ID吗
			
UUID的生成策略: UUID的方式能生成一串唯一随机32位长度数据,它是无序的一串数据,按照开放软件基金会(OSF)制定的标准计算,UUID的生成用到了以太网卡地址.纳秒级时间.芯片ID码和许多可能 ...
 - 记录一下我做Udacity 的Data Scientist  Nano Degree Project
			
做项目的时候看了别人的blog,决定自己也随手记录下在做项目中遇到的好的小知识点. 最近在做Udacity的Data Scientist Nano Degree Project的Customer_Se ...
 - cogs 1254. 最难的任务 Dijkstra + 重边处理
			
1254. 最难的任务 ★ 输入文件:hardest.in 输出文件:hardest.out 简单对比时间限制:1 s 内存限制:128 MB [题目描述] 这个真的很难.算出 123 ...
 - Go中的指针
			
学Java以来,让程序员忽略了指针和内存地址这些概念,Java帮我们封装了对象,简化了对象引用之间的关系.在Go语言中,又帮我们回忆起这些概念. 我们创建的每一个对象在内存中都有一个位置去存储,每个内 ...
 - sleep(),yield(),join(),wait()
			
sleep(),yield(),join(),wait() sleep() sleep是Thread类的静态方法,在指定的时间内让当前线程暂停执行,但不会释放锁标志 也就是使线程进入阻塞状态 wait ...
 - ecshop 管理后台菜单及权限管理机制
			
ecshop 所有的一级菜单选项存放于languages\zh_cn\admin\common.php 文件里面,使用 $_LANG['02_cat_and_goods'] = '商品管理'; 这样 ...
 - Linux--shell练习题
			
1.判断/etc/inittab文件是否大于100行,如果大于,则显示”/etc/inittab is a big file.”否者显示”/etc/inittab is a small file.” ...