bzoj4449 [Neerc2015]Distance on Triangulation

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;
}

 

posted @ 2018-04-03 21:53  zbtrs  阅读(268)  评论(0编辑  收藏  举报