1 条题解

  • 0
    @ 2026-9-26 20:08:12

    为什么题解区只有一篇题解?我来写一篇。


    称在输入数据中输入的点为顶点。可以确定,多边形上的每一个顶点一定都可以找到另一个顶点与它匹配,且匹配方案唯一。

    由于多边形的周长很小,可以直接用数组存储多边形边上的每一个点。

    一条光线从一点射向另一点可以看作在图上在这两点之间建无向边。我们可以用 dsu 维护两点的可到达性。如果两个顶点之间是联通的,那么这两个顶点就可以匹配。

    把多边形逆时针转 45∘45^{\circ},这样光线会平行于坐标轴。将所有点以 xx 为第一关键字,yy 为第二关键字排序尝试靠竖的光线连边,再将所有点以 yy 为第一关键字,xx 为第二关键字排序尝试靠横的光线连边,这样我们就能找到所有匹配。

    另外,光线在某些情况下可以从顶点中穿过去而不被接收,例如样例中从 1010 号顶点射出的光线穿过了 88 号顶点。这种情况需要特判。具体方法就是求出顶点的朝向然后看顶点在这个朝向能不能接到光。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define N 300010
    #define INF 0x3f3f3f3f
    #define lowbit(x) (x&-x)
    #define pii pair<int,int>
    #define cpx complex<double>
    #define poly vector<ll>
    #define get(x) (x?x:n)
    int n,x,y,len[N],la;
    struct node{int x,y,v,idx;}a[N];
    inline bool cmp(const node &n1,const node &n2){return (n1.x!=n2.x)?n1.x<n2.x:n1.y<n2.y;}
    inline bool cmp1(const node &n1,const node &n2){return (n1.y!=n2.y)?n1.y<n2.y:n1.x<n2.x;}
    inline void insert(){
        ++la,a[la] = {x-y,x+y,-1,la};
    }
    int dad[N],dep[N],f[N];
    int find(const int &x){return (dad[x]==x?x:(dad[x] = find(dad[x])));}
    inline void merge(int x,int y){
        x = find(x),y = find(y);
        if(x == y)return ;
        // printf("merging %d %d\n",x,y);
        if(dep[x]<dep[y])swap(x,y);
        dad[y] = x,dep[x] = max(dep[x],dep[y]+1); 
        if(f[x]&&f[y])cout << f[x] << ' ' << f[y] << "\n";
        else if(f[x]||f[y])f[x] += f[y];
    }
    inline void solve(const int &op){
        sort(a+1,a+la+1,op?cmp1:cmp);
        int last = 0;
        for(int i = 1;i <= la;++i){
            if((op && a[i].y != a[i-1].y) || (!op && a[i].x != a[i-1].x))last = 0;
            if(a[i].v >= 0 && (a[i].v)!=op)continue;
            if(!last)last = a[i].idx;
            else merge(a[i].idx,last),last = 0;
        }
    }
    
    // 主函数
    int main(){
        ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
        cin >> n;
        for(int i = 1;i <= n;++i)cin >> x >> y,len[i] = x+y;
        int tmp = len[n];
        for(int i = n;i >= 2;--i)len[i] = len[i]-len[i-1];len[1] = len[1] - tmp;
        x = 0,y = 0;
        for(int i = 1;i <= n;++i){
            if(i & 1){// 动 x
                if(len[i] > 0){
                    for(int j = 0;j < len[i];++j)insert(),++x;
                    a[la-len[i]+1].v = (len[get(i-1)]>0),f[la-len[i]+1] = get(i-1);
                }else{
                    for(int j = 0;j < -len[i];++j)insert(),--x;
                    a[la+len[i]+1].v = (len[get(i-1)]<0),f[la+len[i]+1] = get(i-1);
                }
            }else{
                if(len[i] > 0){
                    for(int j = 0;j < len[i];++j)insert(),++y;
                    a[la-len[i]+1].v = (len[get(i-1)]>0),f[la-len[i]+1] = get(i-1);
                }else{
                    for(int j = 0;j < -len[i];++j)insert(),--y;
                    a[la+len[i]+1].v = (len[get(i-1)]<0),f[la+len[i]+1] = get(i-1);
                }
            }
        }
        cout << (n>>1) << '\n';
        for(int i = 1;i <= la;++i)dad[i] = i,dep[i] = 1;
        a[0] = {-INF,-INF,-INF,-INF};
        solve(0),solve(1);
        return 0;
    }
    
    • 1

    [POI 2008] SZK - Mirror trap玻璃陷阱

    信息

    ID
    2774
    时间
    3000ms
    内存
    64MiB
    难度
    8
    标签
    递交数
    18
    已通过
    5
    上传者