P8596 一个拦的截 题解

· · 题解

令人发指的究极辛巴达多合一题。

给出题人点个赞,数据一点都不水,造出了好多非平凡四元环(

要想做这题,首先你看到这平面图就知道得转对偶,具体在推荐题目第一个矿区的题解里就有。

然后你看到这么一堆位运算就知道要拆位,从高位到低位贪心。

显然,要想拦截成功,从最高位开始:

我们的任务变成了如何求出在某位拦截外星人的代价。显然我们加边权时不会进位,这等价于让一些边获得此位,使得所有含有此位(或者之前放过外星人的位)的边构成割。转成对偶图之后,原图的割等价于新图的环。但是以优于 O(n^2) 的复杂度求无向图的最小环,这我不会啊!

再次观察题面,题目隐含了一个极强的条件:图没有重边!没有重边的平面图边数有上限,为 3n-6,因此原图中不会没有点的度数不大于 5,由于所有边代价一样,我们只要把那个原图中度数最小的点所连的所有边删去,就可以获得每位不大于 5 的代价!

因此,我们可以依次判断新图的最小环是否是 0/1/2/3/4,如果都不是就是 5。具体地,我们依次判断以下条件。

然后这题就做完了,我们发现,这看似友好的题面里面隐藏了好多板子……

下面是一些坑点:

下面是代码,不是很可读,也不能拿来对拍,没啥必要看……

#include<cstdio>
#include<vector>
#include<map>
#include<cstring>
#include<cassert>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
struct par{
    int a,b;
    friend bool operator<(par n1,par n2){if(n1.a==n2.a)return n1.b<n2.b;return n1.a<n2.a;}
};
map<par,int> ppc;
vector<int> l1[165432],l2[165432],sol[135],l3[165432];
int n,m,k,px[165432],py[165432],nxt[305416],t[305416],val[305416],tq[305416],bel[305416],dx[305416],dy[305416],t2[305416],dic[305416],mp[165432],xp[165432],cp[165432],ppv[165432];
bool cmp(int a,int b){
    return atan2(dx[a],dy[a])<atan2(dx[b],dy[b]);
}
bool cmp2(int a,int b){
    return t2[a]<t2[b];
}
int ppcdfs(int now,int arg){
    if(ppv[now])return 0;
    ppv[now]=1;
    int crr=0;
    for(int i=0;i<l1[now].size();i++){
        if(!(val[l1[now][i]]&arg))crr+=ppcdfs(t[l1[now][i]],arg);
    }
    return crr+1;
}
void sv(int now,int arg){
    memset(nxt,-1,sizeof(nxt));memset(bel,-1,sizeof(bel));memset(dic,0,sizeof(dic));memset(t2,0,sizeof(t2));memset(t2,0,sizeof(t2));memset(ppv,0,sizeof(ppv));
    int mid=77777777,mida=0;
    for(int i=1;i<=n;i++){
        int cnt=0,mind=0;
        for(int j=0;j<l1[i].size();j++){
            if(!(val[l1[i][j]]&arg))tq[cnt++]=l1[i][j],mind++;
        }
        mid>mind?mid=mind,mida=i:0;
        sort(tq,tq+cnt,cmp);
        for(int i=0;i<cnt-1;i++)nxt[tq[i]]=tq[i+1]^1;nxt[tq[cnt-1]]=tq[0]^1;
    }
    int cnt=0;
    for(int i=0;i<m*2;i++){
        int nw=i;
        if(nxt[nw]==-1||bel[nw]!=-1)continue;
        cnt++;
        while(!~bel[nw]){
            bel[nw]=cnt;
            nw=nxt[nw];
            dic[cnt]++;
        }
    }
    for(int i=1;i<=cnt;i++)l2[i].clear(),l3[i].clear();
    ppc.clear();
    if(ppcdfs(1,arg)!=n)return;
    if(!mid)return;
    if(mid==1){
        for(int j=0;j<l1[mida].size();j++)if(!(val[l1[mida][j]]&arg))sol[now].push_back(l1[mida][j]);
        return;
    }
    for(int i=0;i<m*2;i++){
        if(bel[i]==-1)continue;
        l2[bel[i]].push_back(i);
        t2[i]=bel[i^1];
        if(bel[i]==bel[i^1]){
            sol[now].push_back(i);
            return;
        }
        if(dic[bel[i^1]]>dic[bel[i]]||(dic[bel[i^1]]==dic[bel[i]]&&bel[i^1]>bel[i]))l3[bel[i]].push_back(i);
    }
    if(mid<=2){
        for(int j=0;j<l1[mida].size();j++)if(!(val[l1[mida][j]]&arg))sol[now].push_back(l1[mida][j]);
        return;
    }
    for(int i=0;i<m*2;i++){
        if(bel[i]==-1)continue;
        if(ppc.find({bel[i],bel[i^1]})!=ppc.end()){
            sol[now].push_back(i);
            sol[now].push_back(ppc[{bel[i],bel[i^1]}]);
            return;
        }
        ppc[{bel[i],bel[i^1]}]=i;
    }
    for(int i=1;i<=cnt;i++){
        sort(l2[i].begin(),l2[i].end(),cmp2);
        for(int j=0;j<l2[i].size()-1;j++){
            assert(t2[l2[i][j]]!=i);
            if(t2[l2[i][j]]==t2[l2[i][j+1]]){
                sol[now].push_back(l2[i][j]);
                sol[now].push_back(l2[i][j+1]);
                return;
            }
        }
    }
    if(mid<=3){
        for(int j=0;j<l1[mida].size();j++)if(!(val[l1[mida][j]]&arg))sol[now].push_back(l1[mida][j]);
        return;
    }
    memset(mp,-1,sizeof(mp));memset(xp,0,sizeof(xp));
    for(int i=1;i<=cnt;i++){
        for(int j=0;j<l3[i].size();j++){
            int ts=t2[l3[i][j]];xp[ts]=i;mp[ts]=l3[i][j];
        }
        for(int j=0;j<l3[i].size();j++){
            int ts=t2[l3[i][j]];
            if(ts==i)continue;
            for(int h=0;h<l3[ts].size();h++){
                if(xp[t2[l3[ts][h]]]==i){
                    sol[now].push_back(l3[ts][h]);
                    sol[now].push_back(mp[t2[l3[ts][h]]]);
                    sol[now].push_back(l3[i][j]);
                    return;
                }
            }
        }
    }
    if(mid<=4){
        for(int j=0;j<l1[mida].size();j++)if(!(val[l1[mida][j]]&arg))sol[now].push_back(l1[mida][j]);
        return;
    }
    memset(cp,-1,sizeof(cp));memset(mp,-1,sizeof(mp));memset(xp,0,sizeof(xp));
    for(int i=1;i<=cnt;i++){
        for(int j=0;j<l2[i].size();j++){
            int ts=t2[l2[i][j]];
            for(int h=0;h<l3[ts].size();h++){
                if(t2[l3[ts][h]]==i)continue;
                if(xp[t2[l3[ts][h]]]==i){
                    sol[now].push_back(cp[t2[l3[ts][h]]]);
                    sol[now].push_back(mp[t2[l3[ts][h]]]);
                    sol[now].push_back(l3[ts][h]);
                    sol[now].push_back(l2[i][j]);
                    return;
                }
                xp[t2[l3[ts][h]]]=i;
                mp[t2[l3[ts][h]]]=l3[ts][h];
                cp[t2[l3[ts][h]]]=l2[i][j];
            }
        }
    }
    if(mid<=5){
        for(int j=0;j<l1[mida].size();j++)if(!(val[l1[mida][j]]&arg))sol[now].push_back(l1[mida][j]);
        return;
    }
    assert(0);
}
signed main(){
    scanf("%*lld%lld%lld%lld",&n,&m,&k);
    for(int i=1;i<=n;i++)scanf("%lld%lld",px+i,py+i);
    for(int i=0;i<m;i++){
        int in1,in2,in3;
        scanf("%lld%lld%lld",&in1,&in2,&in3);
        assert(in1!=in2);
        l1[in1].push_back(i*2);l1[in2].push_back(i*2+1);
        t[i*2]=in2;t[i*2+1]=in1;val[i*2]=val[i*2+1]=in3;
        assert(t[i*2]!=t[i*2+1]);
        dx[i*2]=px[in2]-px[in1];dy[i*2]=py[in2]-py[in1];
        dx[i*2+1]=-px[in2]+px[in1];dy[i*2+1]=-py[in2]+py[in1];
    }
    int cur1=0,cur2=0,anss=44444444,fin=66554432;
    for(int i=30;i>=0;i--){
        sv(i,(1<<i)|cur1);
        if(k&(1<<i))cur2+=sol[i].size();
        else{
            (anss>cur2+sol[i].size())?(anss=(cur2+sol[i].size()),fin=i):0;
            cur1|=(1<<i);
        }
    }
    ppc.clear();
    for(int i=30;i>=fin;i--){
        if(i!=fin&&((k&(1<<i))==0))continue;
        for(int j=0;j<sol[i].size();j++){
            par p1={t[sol[i][j]],t[sol[i][j]^1]};if(p1.a>p1.b)swap(p1.a,p1.b);
            if(ppc.find(p1)==ppc.end())ppc[p1]=(1<<i);
            else ppc[p1]=ppc[p1]|(1<<i);
        }
    }
    printf("%u\n",ppc.size());
    for(auto i=ppc.begin();i!=ppc.end();i++){
        printf("%lld %lld %lld\n",(i->first).a,(i->first).b,i->second);
    }
}