zoukankan      html  css  js  c++  java
  • [NEERC2015]Distance on Triangulation

    考虑多边形三角剖分的实际意义,即一条对角线将一个多边形分为两个。很容易想到分治:每次在当前多边形中选出一条对角线使得两部分点数尽可能均匀,直到当前多边形为三角形为止。

    询问时若两个点在选定的对角线同侧,则递归求解。若在两侧,由于三角剖分的性质,不会有任何一条边穿过此对角线。因此两点间最短路必然穿过对角线端点中的一个。bfs计算每个点到对角线距离即可。

    细节注释在代码里

      1 #include<bits/stdc++.h>
      2 #define ll long long
      3 #define ld long double
      4 using namespace std;
      5 const int N=1002005;
      6 int head[N],dis[2][N],p[N],b[N],h1[N],h2[N],can[N],ans[N],num,cnt,n,m;
      7 struct asd{
      8     int next,to;
      9 }a[N];
     10 struct edge{
     11     int x,y;
     12 }e[N],t1[N],t2[N];
     13 struct Q{
     14     int x,y,id;
     15 }q[N],f1[N],f2[N];
     16 void add(int x,int y){
     17     a[++num].next=head[x];
     18     head[x]=num;
     19     a[num].to=y;
     20 }
     21 void bfs(int s,int l,int r,int *dis){
     22     cnt++;
     23     for(int i=l;i<=r;i++) dis[p[i]]=0x3f3f3f3f,can[p[i]]=cnt;//打标记,只需遍历当前多边形上的点即可
     24     dis[s]=0; queue<int>q; q.push(s);
     25     while(!q.empty()){
     26         int k=q.front();q.pop();
     27         for(int i=head[k];i;i=a[i].next){
     28             if(dis[a[i].to]==0x3f3f3f3f&&can[a[i].to]==cnt){
     29                 dis[a[i].to]=dis[k]+1;
     30                 q.push(a[i].to);
     31             }
     32         }
     33     }
     34 }
     35 void solve(int pl,int pr,int el,int er,int ql,int qr){//  p:点,e:边,q:询问
     36     if(ql>qr||el>er||pl>pr) return ;
     37     int num=0,now=0,Max=0x3f3f3f3f;
     38     for(int i=pl;i<=pr;i++)
     39         b[p[i]]=++num;                               // 将多边形上的点离散化
     40     for(int i=el;i<=er;i++){
     41         int k=b[e[i].y]-b[e[i].x]+1;
     42         if(max(k,pr-pl+3-k)<Max){
     43             Max=max(k,pr-pl+3-k);
     44             now=i;
     45         }
     46     }                                               //找分割边
     47     bfs(e[now].x,pl,pr,dis[0]);bfs(e[now].y,pl,pr,dis[1]);
     48     int n1=0,n2=0;
     49     for(int i=ql;i<=qr;i++){
     50         if(q[i].x>e[now].x&&q[i].y<e[now].y) f1[++n1]=q[i];
     51         else if((q[i].x<e[now].x||q[i].x>e[now].y)&&(q[i].y<e[now].x||q[i].y>e[now].y)) f2[++n2]=q[i];
     52         else ans[q[i].id]=min(ans[q[i].id],min(dis[1][q[i].x]+dis[1][q[i].y],dis[0][q[i].x]+dis[0][q[i].y]));
     53     }
     54     for(int i=1;i<=n1;i++) q[ql+i-1]=f1[i];
     55     for(int i=1;i<=n2;i++) q[ql+n1+i-1]=f2[i];
     56     int n3=0,n4=0,k=p[pr+1],l=p[pr+2];             //对角线端点重复计算在两个多边形里,覆盖掉p[pr+1],p[pr+2]的值,待会要回溯
     57     for(int i=pl;i<=pr;i++){
     58         if(p[i]>=e[now].x&&p[i]<=e[now].y)
     59             h1[++n3]=p[i];
     60         if(p[i]<=e[now].x||p[i]>=e[now].y)
     61             h2[++n4]=p[i];
     62     }
     63     for(int i=1;i<=n3;i++) p[pl+i-1]=h1[i];
     64     for(int i=1;i<=n4;i++) p[pl+n3+i-1]=h2[i];
     65     int n5=0,n6=0;
     66     for(int i=el;i<=er;i++){
     67         if(i==now) continue;
     68         if(e[i].x>=e[now].x&&e[i].y<=e[now].y) t1[++n5]=e[i];
     69         else t2[++n6]=e[i];
     70     }
     71     for(int i=1;i<=n5;i++) e[el+i-1]=t1[i];
     72     for(int i=1;i<=n6;i++) e[el+n5+i-1]=t2[i];
     73     solve(pl,pl+n3-1,el,el+n5-1,ql,ql+n1-1);
     74     solve(pl+n3,pl+n3+n4-1,el+n5,el+n5+n6-1,ql+n1,ql+n1+n2-1);
     75     p[pr+1]=k;p[pr+2]=l;                          //回溯
     76 }
     77 int main(){
     78     int i,j,k,l;
     79     freopen("bsh.in","r",stdin);
     80     freopen("bsh.out","w",stdout);
     81     scanf("%d",&n);
     82     for(i=1;i<=n;i++) p[i]=i;
     83     for(i=1;i<n;i++) add(i,i+1),add(i+1,i);
     84     add(1,n),add(n,1);
     85     for(i=1;i<=n-3;i++){
     86         scanf("%d%d",&k,&l);
     87         if(k>l) swap(k,l);
     88         add(k,l);add(l,k);
     89         e[i].x=k;
     90         e[i].y=l;
     91     }
     92     scanf("%d",&m);
     93     for(i=1;i<=m;i++){
     94         scanf("%d%d",&k,&l);
     95         if(k>l) swap(k,l);
     96         q[i].x=k;
     97         q[i].y=l;
     98         q[i].id=i;
     99         ans[i]=min(l-k,n-(l-k));                   //若k,l为同一个点(且此点不为三角划分的端点),分治不会处理
    100     }                                              //此时ans=0,不赋值也可过,这里是为了保险
    101     solve(1,n,1,n-3,1,m);
    102     for(i=1;i<=m;i++)
    103         printf("%d
    ",ans[i]);
    104     return 0;
    105 }
  • 相关阅读:
    linux 上安装sqlplus
    如何使用 SVN 找到一段时间内提交的代码文件
    nginx 快速检查配置文件的方法
    nginx 报错 [emerg] 1164#1664: bind() to 0.0.0.0:80 failed (10013: An attempt was made to access a socket in a way forbidden by its access permissions)
    nginx 负载均衡
    C#可扩展编程之MEF学习
    5天玩转C#并行和多线程编程
    C#综合揭秘——深入分析委托与事件
    解析C#中[],List,Array,ArrayList的区别及应用
    在easyui datagrid中formatter数据后使用linkbutton
  • 原文地址:https://www.cnblogs.com/jstcao/p/14602891.html
Copyright © 2011-2022 走看看