[WC2013]平面图——平面图点定位

 

[WC2013]平面图 

码农题

平面图点定位:

1.平面图转对偶图:[HNOI2016]矿区

2.扫描线点定位

把所有的顶点和询问点排序,扫描线

每个边在fr的位置加入,to的位置删除,竖直直线不要

用set维护当前的线段,kx+b形式

全局变量X放入重载小于号的比较函数,便于直接比较

到了询问点,直接查询上方第一个线段,得到这个线段所属对偶图新点的编号,即可得到这个询问点的位置

(需要在线就可持久化平衡树吧。。)

 

trick:

A.可以把询问点当做:0*x+p[i].y,直接查询即可

B.避免插入删除时候纵坐标一样的麻烦,X+=0.1后插入,X-=0.1后删除

C.询问上方第一个线段,(我的对偶图内部是顺时针),所以保留to的横坐标比fr的大的边即可,省去了线段重合的麻烦

 

然后求MST之后倍增找到链上最大值即可

 

实现

扫描线时候:

直接开vector把涉及的插入线段,删除线段,询问点直接塞进去,直接查询即可

可能有重边!

这个时候必须保留最小值,先把所有边sort之后再加入。

但是注意:b[++m]=bian(...,...,...m)bian构造函数传进去的m还是之前的m!并没有++m

所以把++m放外面先做

另外,总涉及点数是3*n的。

 [WC2013]平面图——平面图点定位_第1张图片

大致解释

code:并不能过UOJhack数据

#include
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<#define pii pair
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
const int N=1e5+5;
const int inf=0x3f3f3f3f;
int n,m,q;
struct lj{
    int x,y,z;
    bool friend operator <(lj a,lj b){
        return a.z<b.z;
    }
}name[N];
mapint>exi;
//pre---------------------------------------------------------------------------//
struct po{
    double x,y;
    po(){}
    po friend operator -(po a,po b){return po(a.x-b.x,a.y-b.y);}
    po(double xx,double yy){
        x=xx;y=yy;
    }
    bool friend operator <(po a,po b){
        return a.x<b.x;
    }
    double friend operator *(po a,po b){
        return a.x*b.y-a.y*b.x;
    }
}p[3*N];
int num;
double degree(const po &A){
    return atan2(A.y,A.x);
}
struct line{
    int fr,to;
    int cos;
    int id;
    double deg;
    line(){}
    line(int a,int b,int c,int d){fr=a;to=b;cos=c;id=d;deg=degree(p[to]-p[fr]);}
    bool friend operator <(line A,line B){
        return A.deg<B.deg;
    }
}b[2*N];
vectorto[N];
int nxt[2*N];
int nc;//newcur
int be[2*N];
int findnxt(const line &A,const int &id){
    int lp=upper_bound(to[id].begin(),to[id].end(),A)-to[id].begin();
    if(lp==to[id].size()) lp=0;
    return to[id][lp].id;
}
struct edge{
    int x,y,val;
    bool friend operator <(edge a,edge b){
        return a.val<b.val;
    }
}mao[N];
int tot;//count
void trans(){
    for(reg i=1;i<=n;++i) sort(to[i].begin(),to[i].end());
    for(reg i=0;i<=m;++i){
        nxt[i]=findnxt(b[i^1],b[i].to);
    }
    for(reg i=0;i<=m;++i){
        if(be[i]) continue;
        be[i]=be[nxt[i]]=++nc;
        double S=0;
        for(reg j=nxt[i];j!=i;j=nxt[j]){
            be[j]=nc;
            S+=(p[b[j].to]-p[b[i].fr])*(p[b[j].fr]-p[b[i].fr]);
        }   
        if(S<0){
            --nc;
            be[i]=be[nxt[i]]=inf;
            for(reg j=nxt[i];j!=i;j=nxt[j]){
                be[j]=inf;
            }   
        }
    }
    for(reg i=0;i<=m;i+=2){
        if(be[i]!=inf&&be[i^1]!=inf){
            ++tot;
            mao[tot].x=be[i];
            mao[tot].y=be[i^1];
            mao[tot].val=b[i].cos;
        }
    }
}
//trans-------------------------------------------------------------------------//
int gf[N];
int fin(int x){
    return gf[x]==x?x:gf[x]=fin(gf[x]);
}
struct node{
    int nxt,to;
    int val;
}e[2*N];
int hd[N],cnt;
void add(int x,int y,int z){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    e[cnt].val=z;
    hd[x]=cnt;
}
void kruskal(){
    for(reg i=1;i<=nc;++i) gf[i]=i;
    sort(mao+1,mao+tot+1);
    for(reg i=1;i<=tot;++i){
        int x=mao[i].x,y=mao[i].y;
        int k1=fin(x),k2=fin(y);
        if(k1!=k2){
            gf[k1]=k2;
            add(x,y,mao[i].val);
            add(y,x,mao[i].val);
        }
    }
}
//kruskal-------------------------------------------------------------------------//
int dep[N],fa[N][18],mx[N][18];
void dfs(int x,int d){
    dep[x]=d;
    for(reg i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==fa[x][0]) continue;
        fa[y][0]=x;
        mx[y][0]=e[i].val;
        dfs(y,d+1);
    }
}
int query(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    int ret=0;
    for(reg j=17;j>=0;--j){
        if(dep[fa[x][j]]>=dep[y]){
            ret=max(ret,mx[x][j]);x=fa[x][j];
        }
    }
    if(x==y) return ret;
    for(reg j=17;j>=0;--j){
        if(fa[x][j]!=fa[y][j]){
            ret=max(ret,max(mx[x][j],mx[y][j]));
            x=fa[x][j],y=fa[y][j];
        }
    }
    ret=max(ret,max(mx[x][0],mx[y][0]));
    return ret;
}
//dfs&&lca------------------------------------------------------------------------//
double X;
struct bian{
    double k,b;
    int id;
    bian(){}
    bian(double kk,double bb,double dd){
        k=kk;b=bb;id=dd;
    }
    double f(){return k*X+b;}
    bool friend operator <(bian A,bian B){
        return A.f()<B.f();
    }
    void op() const {
        cout<<" k "<" b "<" id "<endl;
    }
};
multisets;
int rk[3*N];
bool cmp(int x,int y){
    return p[x]<p[y];
}
vector<int>qs[3*N];
vectordel[3*N];
vectorins[3*N];
int qa[N],qb[N];
int in[3*N];
int main(){
    rd(n);int lp;rd(lp);
    int x,y;
    for(reg i=1;i<=n;++i){
        rd(x);rd(y);p[++num].x=x;p[num].y=y;
    }
    for(reg i=1;i<=lp;++i){
        rd(name[i].x);rd(name[i].y);rd(name[i].z);if(name[i].x>name[i].y) swap(name[i].x,name[i].y);
    }sort(name+1,name+lp+1);

    m=-1;//warning!! m=-1
    for(reg i=1;i<=lp;++i){
        pii tmp=mk(name[i].x,name[i].y);
        if(exi.count(tmp)) continue;
        exi[tmp]=1;++m;
        b[m]=line(name[i].x,name[i].y,name[i].z,m);
        to[name[i].x].push_back(b[m]);
        ++m;
        b[m]=line(name[i].y,name[i].x,name[i].z,m);
        to[name[i].y].push_back(b[m]);
    }
    trans();
    kruskal();
    dfs(1,1);
    for(reg j=1;j<=17;++j){
        for(reg i=1;i<=nc;++i){
            fa[i][j]=fa[fa[i][j-1]][j-1];
            mx[i][j]=max(mx[i][j-1],mx[fa[i][j-1]][j-1]);
        }
    }
    rd(q);
    for(reg i=1;i<=q;++i){
        po tmp;scanf("%lf",&tmp.x);scanf("%lf",&tmp.y);
        ++num;p[num]=tmp;
        qa[i]=num;
        scanf("%lf",&tmp.x);scanf("%lf",&tmp.y);
        ++num;p[num]=tmp;
        qb[i]=num;
        qs[qa[i]].push_back(qa[i]);
        qs[qb[i]].push_back(qb[i]);
    }
    for(reg i=1;i<=num;++i) rk[i]=i;
    sort(rk+1,rk+num+1,cmp);
    for(reg i=0;i<=m;++i){
        if(p[b[i].fr].x<p[b[i].to].x){
            bian tmp;
            tmp.k=(p[b[i].to].y-p[b[i].fr].y)/(p[b[i].to].x-p[b[i].fr].x);
            tmp.b=p[b[i].fr].y-tmp.k*p[b[i].fr].x;
            tmp.id=i;
            ins[b[i].fr].push_back(tmp);
            del[b[i].to].push_back(tmp);
        }
    }
    for(reg i=1;i<=num;++i){
        int now=rk[i];
        if(del[now].size()){
            X=p[now].x-0.1;
            for(solid y:del[now]){
                auto it=s.find(y);
                s.erase(it);
            }
        }
        if(ins[now].size()){
            X=p[now].x+0.1;
            for(solid y:ins[now]){
                s.insert(y);
            }
        }
        if(qs[now].size()){
            X=p[now].x;
            for(solid y:qs[now]){
                bian tmp=bian(0,p[y].y,233);
                auto it=s.upper_bound(tmp);
                if(it==s.end()){
                    in[y]=inf;
                }else{
                    in[y]=be[(*it).id];
                }
            }
        }
    }
    for(reg i=1;i<=q;++i){
        int x=in[qa[i]];
        int y=in[qb[i]];
        if(x==inf||y==inf){
            puts("-1");
        }else if(x==y){
            puts("0");
        }else{
            printf("%d\n",query(x,y));
        }
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/
View Code

 

转载于:https://www.cnblogs.com/Miracevin/p/10898517.html

你可能感兴趣的:([WC2013]平面图——平面图点定位)