bzoj4449 [Neerc2015]Distance on Triangulation
4449: [Neerc2015]Distance on Triangulation
Time Limit: 100 Sec Memory Limit: 512 MBSubmit: 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
1 5
2 4
5 2
5
1 3
2 5
3 4
6 3
6 6
Sample Output
2
1
1
3
0
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; }