zoukankan      html  css  js  c++  java
  • 【BZOJ 4449】[Neerc2015]Distance on Triangulation 多边形分治结构

    这题好神啊……
    正解方向是分治,据我所知的分治方法有:I.离线后直接对多边形以及所有的询问进行分治 II.建立多边形的分治结构(对于三角形来说类似线段树,对于对角线来说类似平衡树),然后每次在这个分治结构上进行查询 III.将原图转为其对偶图(利用拓扑),发现是一棵树,然后在这棵树上进行分治(似乎也有离线分治和在线建立分治结构两种方法)
    我用的是第二种方法,感觉写起来不是很容易,但是也并不恶心,具体实现以及具体问题的处理方法见代码.
    感觉这样分治的复杂度是log的,实际证明最坏情况下存在使得任意一侧的三角形数不少于n/3的分发,然而并不会证,大该感性理解一下吧.
    思维笔记:I.分治无处不在 II.分治就是分治,也可以没有信息的合并 III.分治的出发点也可以是砍半,就像二分一样 IV.分治结构的建立类似分治,而分治结构的使用更像是二分
    算法笔记:I.建立分治结构时所需信息,以及分治结构所需维护的信息,是不一样的,分开考虑与处理会方便得多 II.在分治结构中,储存信息的方式可以是对于每个点存储其在每一层的信息,也可以是对于每一层存储每个点的信息,两者各有千秋,在这道题里,个人感觉前者用起来更加方便 III.这道题分治的理由我感觉是——一个对角线把多边形切成两个部分,如果询问的两个点都在这两个部分里的其中一个里面,那这次询问一定与另一部分无关

    #pragma GCC optimize("O3")
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define pb push_back
    #define ft first
    #define sd second
    #define mmp(a,b) (std::make_pair(a,b))
    char xB[(1<<15)+10],*xS,*xT;
    #define gtc (xS==xT&&(xT=((xS=xB)+fread(xB,1,1<<15,stdin)),xS==xT)?0:*xS++)
    inline void read(int &x){
      register char ch=gtc;
      for(x=0;ch<'0'||ch>'9';ch=gtc);
      for(;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+ch-'0',ch=gtc);
    }
    typedef std::pair<int,int> pii;
    typedef std::vector<int> vi;
    typedef std::vector<pii> vii;
    const int A=30,N=52000,Inf=0x3f3f3f3f;
    vi tmp1;
    vii tmp2;
    struct Block{
      Block *ch[2];
      pii cut;
    }*root,block[N<<2];
    #define newblock (block+(sz++))
    int to[N][A],dis[N][A][2];
    int q[N],front,back,vis[N],id[N];
    int n;
    struct V{int to,next;}c[N<<2];
    int head[N],t;
    inline void add(int x,int y){
      c[++t].to=y,c[t].next=head[x],head[x]=t;
      c[++t].to=x,c[t].next=head[y],head[y]=t;
    }
    int sz,cnt;
    inline void bfs(int S,int deep,int opt){
      ++cnt,front=back=0,q[back++]=S;
      dis[S][deep][opt]=0,vis[S]=cnt;
      register int x,i;
      while(front!=back){
        x=q[front++];
        for(i=head[x];i;i=c[i].next)
          if(vis[c[i].to]!=cnt){
            vis[c[i].to]=cnt;
            dis[c[i].to][deep][opt]=dis[x][deep][opt]+1;
            q[back++]=c[i].to;
          }
      }
    }
    inline void build(Block *&p,register vi poi,register vii cut,int deep){
      p=newblock;
      if(cut.size()==0)return;
      pii mini;
      int min=Inf,temp,size1=poi.size(),size2=cut.size();
      register int i;
      for(i=0;i<size2;++i){
        temp=std::abs(id[cut[i].ft]-id[cut[i].sd])+1;
        temp=std::max(temp,size1-temp+2);
        if(temp<min)
          min=temp,mini=cut[i];
      }
      p->cut=mini;
      int l=id[mini.ft],r=id[mini.sd];
      if(l>r)std::swap(l,r);
      tmp1.clear(),tmp2.clear();
      for(i=0;i<=l;++i){
        tmp1.pb(poi[i]);
        id[poi[i]]=tmp1.size()-1;
        to[poi[i]][deep]=1;
      }
      for(i=r;i<size1;++i){
        tmp1.pb(poi[i]);
        id[poi[i]]=tmp1.size()-1;
        to[poi[i]][deep]=1;
      }
      for(i=0;i<size2;++i){
        if(cut[i]==mini)continue;
        if(to[cut[i].ft][deep]==1&&to[cut[i].sd][deep]==1)
          tmp2.pb(cut[i]);
      }
      build(p->ch[1],tmp1,tmp2,deep+1);
      tmp1.clear(),tmp2.clear();
      for(i=l;i<=r;++i){
        tmp1.pb(poi[i]);
        id[poi[i]]=i-l;
        to[poi[i]][deep]=0;
      }
      for(i=0;i<size2;++i){
        if(cut[i]==mini)continue;
        if(to[cut[i].ft][deep]==0&&to[cut[i].sd][deep]==0)
          tmp2.pb(cut[i]);
      }
      build(p->ch[0],tmp1,tmp2,deep+1);
      for(i=0;i<size1;++i)head[poi[i]]=0;
      t=0;
      for(i=1;i<size1;++i)
        add(poi[i],poi[i-1]);
      add(poi[size1-1],poi[0]);
      for(i=0;i<size2;++i)
        add(cut[i].ft,cut[i].sd);
      bfs(mini.ft,deep,0);
      bfs(mini.sd,deep,1);
    }
    inline int query(Block *p,int x,int y,int deep){
      if(!p->ch[0])return 1;
      if(p->cut.ft==x)return dis[y][deep][0];
      if(p->cut.sd==x)return dis[y][deep][1];
      if(p->cut.ft==y)return dis[x][deep][0];
      if(p->cut.sd==y)return dis[x][deep][1];
      if(to[x][deep]==to[y][deep])return query(p->ch[to[x][deep]],x,y,deep+1);
      int ret=dis[x][deep][0]+dis[y][deep][0];
      ret=std::min(ret,dis[x][deep][1]+dis[y][deep][1]);
      return ret;
    }
    int main(){
      read(n);
      register int i;pii rio;
      for(i=1;i<=n;++i)
        tmp1.pb(i),id[i]=i-1;
      for(i=1;i<=n-3;++i)
        read(rio.ft),read(rio.sd),tmp2.pb(rio);
      build(root,tmp1,tmp2,1);
      int T,x,y;
      read(T);
      while(T--){
        read(x),read(y);
        printf("%d
    ",x==y?0:query(root,x,y,1));
      }
      return 0;
    }
  • 相关阅读:
    一些常用的库[转载]
    《三国演义》很给力演绎60条职场真理
    保证你现在和未来不失业的10种关键技【转载】
    百度面试题
    百度的一到算法i题
    FindMaxDeep
    csinglelink
    FindLongArray
    byte转hex,hex转byte
    获取异常信息
  • 原文地址:https://www.cnblogs.com/TSHugh/p/8543083.html
Copyright © 2011-2022 走看看