1. 程式人生 > >bzoj4449 [Neerc2015]Distance on Triangulation

bzoj4449 [Neerc2015]Distance on Triangulation

submit truct ret tar namespace dfs 分享 ref IT

4449: [Neerc2015]Distance on Triangulation

Time Limit: 100 Sec Memory Limit: 512 MB
Submit: 205 Solved: 69
[Submit][Status][Discuss]

Description

給定一個凸n邊形,以及它的三角剖分。再給定q個詢問,每個詢問是一對凸多邊行上的頂點(a,b),問點a最少經過多少條邊(可以是多邊形上的邊,也可以是剖分上的邊)可以到達點b。

Input

第一行一個整數n(n <= 50000),代表有n個點。點1,2,3,…,n是凸多邊形上是順時針排布的。

接下來n-3行,每行兩個整數(x,y),代表(x,y)之間有一條剖分邊。 接下來是一個整數q(q <= 100000),代表有q組詢問。 接下來q行是兩個整數(a,b)。

Output

輸出q行,每行一個整數代表最少邊數。

Sample Input

6
1 5
2 4
5 2
5
1 3
2 5
3 4
6 3
6 6

Sample Output

2
1
1
3
0
分析:這題太神了......    做法上和bzoj4456是一樣的,但是代碼很難寫.    分界線上的兩個點是要同時出現在左區間和右區間的.分治後左區間+右區間的長度就不等於原區間的長度了. 怎麽辦呢? 往右擴展唄.技術分享圖片,重疊的這部分的元素實際上屬於左區間,右區間占著這些位置罷了. 這樣就有一個問題:如果先處理左區間,再處理右區間,本該屬於左區間的重疊部分就會被右區間給占了,這是不合法的,所以只有先處理右區間才行. 數組要開2倍才行.
   血的教訓:dfs時不要開全局變量(如果不是統計最優解/答案的話).    優化:bfs代替dijkstra. 每次只松弛在當前區間內的點.
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 2000010,inf = 0x7fffffff;
int n,head[maxn],to[maxn],nextt[maxn],tot = 1
,a[maxn],Q,ans[maxn],d[maxn][2],Tim,vis[maxn]; int cnt1,cnt2,cnt3,cnt4,cnt5,cnt6,tmp3[maxn],tmp4[maxn],num; struct node { int x,y,id; } e[maxn],q[maxn],tmp1[maxn],tmp2[maxn],tmp5[maxn],tmp6[maxn]; void add(int x,int y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } int find(int l,int r,int pos) { int anss = 0; while (l <= r) { int mid = (l + r) >> 1; if (a[mid] == pos) { anss = mid; break; } if (a[mid] < pos) l = mid + 1; else r = mid - 1; } return anss; } int getans(int x,int y) { int temp = inf; temp = min(d[x][0] + d[y][0],temp); temp = min(d[x][1] + d[y][1],temp); temp = min(d[x][0] + d[y][1] + 1,temp); temp = min(d[x][1] + d[y][0] + 1,temp); return temp; } void bfs(int S,int l,int r,int opt) { Tim++; vis[S] = Tim; queue <int> q; q.push(S); d[S][opt] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i; i = nextt[i]) { int v = to[i]; if (a[find(l,r,v)] == v && vis[v] != Tim) { vis[v] = Tim; q.push(v); d[v][opt] = d[u][opt] + 1; } } } } void solve(int l1,int r1,int l2,int r2,int l3,int r3) //對角線,點,詢問 { if (l3 > r3) return; int cnt1 = 0,cnt2 = 0,cnt3 = 0,cnt4 = 0,cnt5 = 0,cnt6 = 0; node res = e[l1]; int maxx = inf,cur; for (int i = l1; i <= r1; i++) { int x = find(l2,r2,e[i].x),y = find(l2,r2,e[i].y); if (x > y) swap(x,y); int temp = max(y - x,r2 - l2 + 1 - (y - x)); if (temp < maxx) { maxx = temp; res = e[i]; cur = i; } } int X = res.x,Y = res.y; bfs(X,l2,r2,0); bfs(Y,l2,r2,1); for (int i = l3; i <= r3; i++) { if (q[i].x == X && q[i].y == Y) { ans[q[i].id] = 1; continue; } ans[q[i].id] = min(ans[q[i].id],getans(q[i].x,q[i].y)); if (q[i].x > X && q[i].x < Y && q[i].y > X && q[i].y < Y) tmp5[++cnt5] = q[i]; else if ((q[i].x < X || q[i].x > Y) && (q[i].y < X || q[i].y > Y)) tmp6[++cnt6] = q[i]; } for (int i = l1; i <= r1; i++) { if (cur == i) continue; if (e[i].x >= X && e[i].y <= Y) tmp1[++cnt1] = e[i]; else tmp2[++cnt2] = e[i]; } for (int i = l2; i <= r2; i++) { if (a[i] >= X && a[i] <= Y) tmp3[++cnt3] = a[i]; if (a[i] <= X || a[i] >= Y) tmp4[++cnt4] = a[i]; } for (int i = 1; i <= cnt1; i++) e[l1 + i - 1] = tmp1[i]; for (int i = 1; i <= cnt2; i++) e[l1 + cnt1 + i - 1] = tmp2[i]; for (int i = 1; i <= cnt3; i++) a[l2 + i - 1] = tmp3[i]; for (int i = 1; i <= cnt4; i++) a[l2 + cnt3 + i - 1] = tmp4[i]; for (int i = 1; i <= cnt5; i++) q[l3 + i - 1] = tmp5[i]; for (int i = 1; i <= cnt6; i++) q[l3 + cnt5 + i - 1] = tmp6[i]; solve(l1 + cnt1,l1 + cnt1 + cnt2 - 1,l2 + cnt3,l2 + cnt3 + cnt4 - 1,l3 + cnt5,l3 + cnt5 + cnt6 - 1); solve(l1,l1 + cnt1 - 1,l2,l2 + cnt3 - 1,l3,l3 + cnt5 - 1); } int main() { memset(ans,127 / 3,sizeof(ans)); scanf("%d",&n); for (int i = 1; i <= n; i++) a[i] = i; for (int i = 1; i <= n - 3; i++) { int x,y; scanf("%d%d",&x,&y); if (x > y) swap(x,y); add(x,y); add(y,x); e[i].x = x; e[i].y = y; } for (int i = 1; i <= n; i++) { add(i,i % n + 1); add(i % n + 1,i); } scanf("%d",&Q); for (int i = 1; i <= Q; i++) { int x,y; scanf("%d%d",&x,&y); if (x > y) swap(x,y); if (x == y) ans[i] = 0; else if (x % n + 1 == y || y % n + 1 == x) ans[i] = 1; else { q[++num].x = x; q[num].y = y; q[num].id = i; ans[i] = min(ans[i],min(y - x,n + x - y)); } } solve(1,n - 3,1,n,1,num); for (int i = 1; i <= Q; i++) printf("%d\n",ans[i]); return 0; }

bzoj4449 [Neerc2015]Distance on Triangulation