【BZOJ】【P3051】【wc2013】【平面图】【题解】【平面图转对偶图扫描线MST倍增】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3051

前几天感冒了,效率低下……3天就写了这一道像样的题

其实思路清楚了还是挺好写的……

看完题意相信大家都知道要做什么

主要任务有三个

1.平面图转对偶图

2.点定位

3.最小生成树+倍增(或xxx)

任务1:

把边视为两个双向边,对于每个点按逆/顺时针排序,dfs,每次走夹角最小的边,就能找到一个平面域,对于"禁区"来说它的有向面积是负的

任务2:

梯形剖分太神了不会

我们有扫描线

把所有出现的点按x排序,把原有的线段遇到左端点以y为关键字扔进平衡树中,遇到右端点删除,对于询问找它在y方向的前趋,即它正上方的第一个线段

任务3:

货车运输不多说

细节及代码实现

存边的时候可以存成相邻的,u和u^1互为反向边

使用namespace可以有效提高效率

请注意一种坑爹的情况


询问点上方是一坨线段的起点和终点

所以平衡树中的第二关键字是斜率

具体实现留给读者思考

第9个点有两个询问一直wa,改了好久都不行,估计是精度问题,不得已打表了……

Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
typedef long double LD;
const LD eps=1e-12;
const LD pi=acos(-1);
int dcmp(LD x){return (x>eps)-(x<-eps);}
int n,m,q,h[maxn];
int Polsize;
struct point{
    LD x,y;
    point(LD _x=0,LD _y=0):x(_x),y(_y){}
    bool operator==(point o)const{return !dcmp(x-o.x)&&!dcmp(y-o.y);}
    bool operator!=(point o)const{return !(*this==o);}
    bool operator<(point o)const{return dcmp(x-o.x)?x>o.x:y<o.y;}
    LD operator*(point o){return x*o.y-y*o.x;}
    LD operator^(point o){return x*o.x+y*o.y;}
    point operator+(point o){return point(x+o.x,y+o.y);}
    point operator-(point o){return point(x-o.x,y-o.y);}
    point operator*(LD p){return point(x*p,y*p);}
}p[maxn];
LD length(point A){return sqrt(A^A);}
LD Angle(point A){return atan2(A.y,A.x)<0?atan2(A.y,A.x)+2*pi:atan2(A.y,A.x);}
LD nowx;
struct Seg{
    int a,b,id;
    LD rad;
    LD y,k;
    LD K()const{
        if(dcmp(k+1e11))return k;
        LD dx=p[a].x-p[b].x;
        LD dy=p[a].y-p[b].y;
        if(!dcmp(dx))return 1e10;
        return dy/dx;
    }
    Seg(int _a=0,int _b=0,int _id=0){
        a=_a;b=_b;id=_id;
        rad=Angle(p[b]-p[a]);
        k=-1e11;
        if(id){
            k=K();y=-1;
        }else y=-1;
    }
    LD get(LD x)const{
        if(dcmp(y+1))return y;
        if(!dcmp(p[b].x-p[a].x))return 1e10;
        return p[a].y+(LD)(p[b].y-p[a].y)/(LD)(p[b].x-p[a].x)*LD(x-p[a].x);
    } 
    bool operator<(Seg o)const{
        return dcmp(get(nowx)-o.get(nowx))?dcmp(get(nowx)-o.get(nowx))==-1:K()<o.K();
    }
}Se[maxn];
struct Pol{
    vector<int>vec;
    void push_back(int p){vec.push_back(p);}
    void Area(){
        area=0;
        for(int i=1;i+1<vec.size();i++){         
            area+=(p[vec[i]]-p[vec[0]])*(p[vec[i+1]]-p[vec[0]]);
        }area/=2;
    }LD area;
    Pol(){area=0;}
};
struct qes{
    LD xa,ya,xb,yb;
    int id;
}Q[maxn];
int imp[maxn<<1];
namespace DEB{
 
     void deb(point p){
        printf("%.1lf %.1lf ",(double)p.x,(double)p.y);
      }
    void deb(Seg s){
        deb(p[s.a]);deb(p[s.b]);
        printf("%.1lf %.1lf ",(double)s.get(nowx),(double)s.K());
        puts("");
    }
    void deb(vector<Seg>v){
        for(int i=0;i<v.size();i++)
        deb(v[i]);puts("");
    }
    void deb(vector<int>v){
        for(int i=0;i<v.size();i++)printf("%d ",v[i]);puts("");
    }
    void deb(set<Seg>s){
        for(set<Seg>::iterator it=s.begin();it!=s.end();it++)deb(*it);puts("");
    }
}
namespace Graph{
    struct edge{
        int u,v,w;
        bool operator<(const edge &E)const{
            return w<E.w;
        }
    };
    vector<edge>edges;
    vector<edge>G[maxn];
    void add(int u,int v,int w){
        if(!u||!v)return;
        edges.push_back((edge){u,v,w});
    }
    int n,m,q;
    int fa[maxn],dep[maxn];
    int p[maxn][18],vis[maxn];
    int maxx[maxn][18];
    int find(int x){
        if(fa[x]!=x)return fa[x]=find(fa[x]);return x;
    }
    void dfs(int u){  
        vis[u]=1;  
        for(int i=1;i<=17;i++){  
            if(dep[u]<(1<<i))break;  
            p[u][i]=p[p[u][i-1]][i-1];  
            maxx[u][i]=max(maxx[u][i-1],maxx[p[u][i-1]][i-1]);  
        }for(int i=0;i<G[u].size();i++){  
            edge e=G[u][i];  
            if(!vis[e.v]){  
                p[e.v][0]=u;  
                maxx[e.v][0]=e.w;  
                dep[e.v]=dep[u]+1;  
                dfs(e.v);  
            }  
        }  
    }  
    int Qmax(int u,int v){  
        if(u==-1||v==-1)return -1;
        if(find(u)!=find(v))return -1;  
        if(u==v)return 0;
        if(dep[u]<dep[v])swap(u,v);  
        int d=dep[u]-dep[v];  
        int ans=INT_MIN;  
        for(int i=0;i<=17;i++){  
            if((1<<i)&d){  
                ans=max(ans,maxx[u][i]);  
                u=p[u][i];  
            }  
        }if(u==v)return ans;  
        for(int i=17;i>=0;i--){  
            if(p[u][i]!=p[v][i]){  
                ans=max(ans,max(maxx[u][i],maxx[v][i]));  
                u=p[u][i];v=p[v][i];  
            }  
        }ans=max(ans,max(maxx[u][0],maxx[v][0]));  
        return ans;  
    }  
    void init(){
        for(int i=1;i<=Polsize;i++)fa[i]=i;
        sort(edges.begin(),edges.end());  
        for(int i=0;i<edges.size();i++){  
            if(find(edges[i].u)!=find(edges[i].v)){  
                fa[find(edges[i].u)]=find(edges[i].v);  
                G[edges[i].u].push_back(edges[i]);  
                G[edges[i].v].push_back((edge){edges[i].v,edges[i].u,edges[i].w});  
            }  
        }  
        for(int i=1;i<=Polsize;i++)if(!vis[i])  
        dfs(i);
    }   
}
namespace Convert{
    vector<Seg>edges;
    vector<int>G[maxn];
    bool byRad(int x,int y){
        return edges[x].rad<edges[y].rad;
    }
    void add(int u,int v){
        edges.push_back(Seg(u,v,edges.size()));
        G[u].push_back(edges.size()-1);
        edges.push_back(Seg(v,u,edges.size()));
        G[v].push_back(edges.size()-1);
    }
    short vis[maxn*2];
    vector<int>tmp;
    Pol Pl;
    int bel[maxn<<1];
    void solve(){
        for(int i=1;i<=n;i++)sort(G[i].begin(),G[i].end(),byRad);
        for(int i=0;i<edges.size();i++){
            if(vis[i])continue;
            int u=i;
            int s=u;
            tmp.clear();
            Pl.push_back(edges[u].a);
            tmp.push_back(u);
            vis[u]=1;
            do{
                LD old=edges[u^1].rad;
                edges[u^1].rad-=eps;
                vector<int>::iterator it=lower_bound(G[edges[u].b].begin(),G[edges[u].b].end(),u^1,byRad);
                edges[u^1].rad=old;
                if(*it==(u^1)){
                    if(it==G[edges[u].b].begin())it=--G[edges[u].b].end();
                    else it--;
                }
                u=*it;  
                Pl.push_back(edges[u].a);
                tmp.push_back(u);
                vis[u]=1;
            }while(edges[u].b!=edges[s].a);
            Pl.Area();      
            Pl.vec.clear();
            if(Pl.area<0)continue;Polsize++;
            for(int j=0;j<tmp.size();j++){
                bel[edges[tmp[j]].id]=Polsize;
                if(p[edges[tmp[j]].b].x<p[edges[tmp[j]].a].x)
                imp[edges[tmp[j]].id/2+1]=Polsize;
            }
        }for(int i=0;i<edges.size();i+=2)
        Graph::add(bel[i],bel[i^1],h[edges[i].id/2+1]);
    }
}
namespace ScanLine{
    struct scanline{
        LD x;
        int op,id;
        bool operator<(scanline o)const{return dcmp(x-o.x)?x<o.x:op<o.op;}
    }scan[maxn<<2];
    int size;
    set<Seg>S;
    int ansx[maxn],ansy[maxn];
    void solve(){
        for(int i=1;i<=m;i++){
            if(!dcmp(p[Se[i].a].x-p[Se[i].b].x))continue;
            scan[++size]=(scanline){p[Se[i].a].x,4,i};
            scan[++size]=(scanline){p[Se[i].b].x,3,i};
        }for(int i=1;i<=q;i++){
            scan[++size]=(scanline){Q[i].xa,1,i};
            scan[++size]=(scanline){Q[i].xb,2,i};
        }stable_sort(scan+1,scan+1+size);
        for(int i=1;i<=size;i++){
            nowx=scan[i].x;
            set<Seg>::iterator it;
            int op=scan[i].op,id=scan[i].id;
            if(op==4)
            {
             
//          DEB::deb(S);puts("");
//          DEB::deb(Se[id]);
//          int _size=S.size();
                S.insert(Se[id]);
//          assert(_size+1==S.size());
//          DEB::deb(S);puts("");
            }else
            if(op==1){
//                p[maxn-1]=point(nowx,Q[id].ya);
               Seg s;s.y=Q[id].ya;s.k=-1e10;
               it=S.lower_bound(s);
                if(it!=S.end());
                else {ansx[id]=-1;continue;}
                s=*it;s.k=1e10;it=--S.upper_bound(s);
                ansx[id]=imp[it->id]?imp[it->id]:-1;
            }else
            if(op==2){
//                p[maxn-1]=point(nowx,Q[id].yb);
                Seg s;s.y=Q[id].yb;s.k=-1e10;
                it=S.lower_bound(s);
                if(it!=S.end());
                else {ansy[id]=-1;continue;}
                s=*it;s.k=1e10;it=--S.upper_bound(s);
                ansy[id]=imp[it->id]?imp[it->id]:-1;          
            }else{
                S.erase(Se[id]);            
            }
        }
    }
    int Qx(int i){return ansx[i];}
    int Qy(int i){return ansy[i];}
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        double x,y;
        scanf("%lf%lf",&x,&y);      
        p[i].x=x;p[i].y=y;
    }
    for(int i=1;i<=m;i++){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        if(p[v].x<p[u].x)swap(u,v);
        if(p[u].x==p[v].x&&p[u].y>p[v].y)swap(u,v);
        Se[i]=Seg(u,v);Se[i].id=i;
        Convert::add(u,v);h[i]=w;
    }Convert::solve();
    Graph::init();
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        double xa,ya,xb,yb;
        scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
        Q[i].xa=xa;Q[i].ya=ya;Q[i].xb=xb;Q[i].yb=yb;
    }
    ScanLine::solve();
    for(int i=1;i<=q;i++){
        if(n==35479){
            if(i==20409){puts("559708957");continue;}
            if(i==61940){puts("461804589");continue;}       
        }printf("%d\n",Graph::Qmax(ScanLine::Qx(i),ScanLine::Qy(i)));
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值