CF1282E

在机房和 Alex_Wei 无聊做 2500 的题,做不动然后做这个 2400 的题。然后吊打他了,他到 8:00 下课还没做出来,而我则在 8:01 AC 了。吊打 2512 GM,爽(

学校 407 机房电脑上竟然没有 devc++,于是代码是在 CF 上的 custom test 里写的/kk


Portal

注意到,对于任意一种三角剖分方法,一定有一个三角形是连接相邻三个顶点的,这是异常显然的。考虑从这个三角形入手,显然这个三角形连接的三个点中间那个只会在共 (3(n-2)) 个数中出现一遍。于是我们可以找到这个出现一遍的点(如果有多个则选择任意一个),将这个三角形删掉,这样得到了一个大小为 (n-1) 的多边形,咦,可以顺着这个思路归纳下去了。

就一直删直到大小为 (3) 为止。那么剖分顺序显然就是删除顺序。至于顶点顺序,考虑若 (n-1) 的答案是序列 (a),然后删掉的那个三角形从左到右分别是 (x,y,z)。那么显然在 (a)(x,z) 是(环形)相邻的,那么只需要将 (y) 插入它们两个之间就可以得到 (n) 的顶点顺序。

接下来考虑实现。难点在于如何每次快速找到仅出现一次的点,和如何快速在两个数中间插入一个数。

  • 如何每次快速找到仅出现一次的点:考虑类似拓扑排序的流程,维护一个队列,里面装当前没被处理过的仅出现一次的点。然后用当前点去更新别人出现次数,如果有被减成 (1) 的就压入。由于保证有解,所以肯定能进行到最后。
  • 如何快速在两个数中间插入一个数:考虑暴力平衡树(大雾)。考虑链表。但是链表不支持随机访问啊,没关系,你会发现就算支持随机访问你也不会做。注意到你不需要根据下标访问,你只需要根据值来访问(你需要找到 (x)(z)),而值所对应地址显然是不会变的,于是每插入一个值就存下它的地址就好了。

线性。

(发现缩进是空鸽哦)

#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define X first
#define Y second
#define pb push_back
const int N=100000;
int n;
int a[N+1],b[N+1],c[N+1];
vector<int> hav[N+1];
bool del[N+1];
int cnt[N+1];
vector<pair<int,pair<int,int> > > v;
list<int>::iterator it[N+1];
list<int>::iterator operator+(list<int>::iterator x,int){return ++x;}
void mian(){
    cin>>n;
    //clear
    for(int i=1;i<=n;i++)hav[i].clear();
    memset(del,0,sizeof(del)),memset(cnt,0,sizeof(cnt));
    v.clear();
    for(int i=1;i<=n-2;i++)
        scanf("%d%d%d",a+i,b+i,c+i),
        cnt[a[i]]++,cnt[b[i]]++,cnt[c[i]]++,
        hav[a[i]].pb(i),hav[b[i]].pb(i),hav[c[i]].pb(i);
    queue<int> q;
    for(int i=1;i<=n;i++)if(cnt[i]==1)q.push(i);
    vector<int> ans2;
    for(int i=1;i<n-2;i++){
        int x=q.front();
        q.pop();
        for(int i=0;i<hav[x].size();i++)if(!del[hav[x][i]]){
            int fd=hav[x][i];
            ans2.pb(fd);
            if(b[fd]==x)swap(a[fd],b[fd]);
            else if(c[fd]==x)swap(a[fd],c[fd]);
            v.pb(mp(x,mp(b[fd],c[fd])));
            del[fd]=true;
            if(--cnt[b[fd]]==1)q.push(b[fd]);
            if(--cnt[c[fd]]==1)q.push(c[fd]);
            break;
        }
    }
    list<int> lis;
    for(int i=1;i<=n-2;i++)if(!del[i]){
        ans2.pb(i);
        lis.pb(a[i]),it[a[i]]=--lis.end();
        lis.pb(b[i]),it[b[i]]=--lis.end();
        lis.pb(c[i]),it[c[i]]=--lis.end();
    }
    for(int i=n-4;~i;i--){
        int x=v[i].X,l=v[i].Y.X,r=v[i].Y.Y;
        if(it[l]+1==it[r]||it[l]==--lis.end()&&it[r]==lis.begin())
            lis.insert(it[l]+1,x),it[x]=it[l]+1;
        else lis.insert(it[r]+1,x),it[x]=it[r]+1;
    }
    for(list<int>::iterator i=lis.begin();i!=lis.end();i++)printf("%d ",*i);puts("");
    for(int i=0;i<ans2.size();i++)printf("%d ",ans2[i]);puts("");
}
int main(){
    int testnum;
    cin>>testnum;
    while(testnum--)mian();
    return 0;
}
原文地址:https://www.cnblogs.com/ycx-akioi/p/cf1282e-solution.html