NOI 可能会做的题 选做

由于重启电脑以后所有东西都没了因此还要重写一遍。

每天使用的算草数量确实是上了个数量级。

“你都敢拿小刀往胳膊上划为什么不敢吃这个(指魔芋爽)”——H_Kaguya 睿频 gtm1514。不过我觉得吃辣也不会让人精神状态 ++ 吧。不过我的小刀现在彻底成为破伤风之刃了,我就扔了。

吗了,吃了四分之一袋魔芋爽喝了一瓶水,喝都喝饱了。今天晚上两个小时已经喝了两瓶半水了!(7.8)

感觉很大程度上失去了活着的意义。昨天中午路上和 abhwolxq 的一些谈话似乎也能说明。其实不如说从来没有过。打算探讨一下。同时也应该找时间拜读一下《查拉图斯特拉如是说》。

Summer lasts no more,we won't slumber to the past we adore.
残暑已褪,我们亦不会沉溺于所爱的往昔

[NOI2020] 超现实树

某科学的超现实树。这题也挺超现实的。不过不是不可做。

首先通过考虑在一个叶子上不断挂单向链的情况可以发现只有左右子树大小最小值不超过 \(1\) 的有贡献。

然后看树的形式感觉上就是个递归东西。首先只有一个节点肯定几乎完备。看有多层的情况。对于一层,考虑在根节点挂链的情况,发现必须有至少一个满足左右子树都几乎完备,然后是根节点没东西的情况,必须满足只有一个子树。

具体的说就是四个情况:只有左 / 右子树且几乎完备,同时有左右子树且几乎完备。四个情况必须都有树满足,直接递归扫。或者说有单独节点则直接满足。

具体实现可以把上边四种情况看做树的四个叉,每棵树往下递归把树塞进去,需要所有叶子都几乎完备。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
using namespace std;
int n,rt,t,lson[2000010],rson[2000010],son[2000010][4];
bool vis[2000010];
bool check(int rt){
    if(!lson[rt]&&!rson[rt])return true;
    return check(lson[rt])||check(rson[rt]);
}
void merge(int &rt,int x){
    if(!rt)rt=++t;
    if(!lson[x]&&!rson[x]){
        vis[rt]=true;return;
    }
    if(!rson[x])merge(son[rt][0],lson[x]);
    if(!lson[x])merge(son[rt][1],rson[x]);
    if(!lson[rson[x]]&&!rson[rson[x]]&&lson[x]&&rson[x])merge(son[rt][2],lson[x]);
    if(!lson[lson[x]]&&!rson[lson[x]]&&lson[x]&&rson[x])merge(son[rt][3],rson[x]);
}
bool getans(int rt){
    if(!rt)return false;
    if(vis[rt])return true;
    return getans(son[rt][0])&&getans(son[rt][1])&&getans(son[rt][2])&&getans(son[rt][3]);
}
int main(){
    int tim;scanf("%d",&tim);
    while(tim--){
        int x;scanf("%d",&x);
        while(x--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++)scanf("%d%d",&lson[i],&rson[i]);
            if(!check(1))continue;
            merge(rt,1);
        }
        puts(getans(1)?"Almost Complete":"No");
        for(int i=1;i<=t;i++)son[i][0]=son[i][1]=son[i][2]=son[i][3]=vis[i]=0;
        rt=t=0;
    }
    return 0;
}
posted @ 2023-07-09 08:40  gtm1514  阅读(47)  评论(3编辑  收藏  举报