CCPC-Wannafly Winter Camp Day4 Div1 - 最小边覆盖 - [线段树]

题目链接:https://zhixincode.com/contest/18/problem/C?problem_id=261

样例输入 1

4 2
1 2
3 4

样例输出 1

Yes

样例输入 2

4 3
1 2
2 3
3 4

样例输出 2

No

题解:

判断一个边集是否为最小边覆盖,用最笨的方法,暴力枚举边集内所有边进行删除,看删除后是否依然覆盖所有点,这个可以用线段树优化成 $O(\log n)$ 的时间复杂度,就可以过了。这是一个比较直观的做法。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define x(p) (p.first)
#define y(p) (p.second)
const int maxn=2e5+10;
const int maxm=3e5+10;

int n,m;
int d[maxn];
pii e[maxm];

#define ls (rt<<1)
#define rs (rt<<1|1)
struct Node{
    int l,r;
    int val;
    bool ok;
}o[maxn<<2];
void pushup(int rt)
{
    o[rt].val=o[ls].val+o[rs].val;
    o[rt].ok=o[ls].ok&o[rs].ok;
}
void build(int rt,int l,int r)
{
    o[rt].l=l, o[rt].r=r;
    if(l==r)
    {
        o[rt].val=d[l];
        o[rt].ok=(o[rt].val>0);
        return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(rt);
}
void update(int rt,int pos,int val)
{
    if(o[rt].l==o[rt].r)
    {
        o[rt].val+=val;
        o[rt].ok=(o[rt].val>0);
        return;
    }
    int mid=(o[rt].l+o[rt].r)>>1;
    if(pos<=mid) update(ls,pos,val);
    if(pos>mid) update(rs,pos,val);
    pushup(rt);
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>x(e[i])>>y(e[i]);
        d[x(e[i])]++, d[y(e[i])]++;
    }

    build(1,1,n);
    bool ans=o[1].ok;
    if(!ans) cout<<"No\n";
    else
    {
        for(int i=1;i<=m;i++)
        {
            update(1,x(e[i]),-1), update(1,y(e[i]),-1);
            if(o[1].ok) {ans=0; break;}
            update(1,x(e[i]),1), update(1,y(e[i]),1);
        }
        cout<<(ans?"Yes":"No")<<'\n';
    }
}

另一个题解:

然后仔细想一下上面的思路,就会发现有点蠢。因为删掉一条边,若依然能覆盖所有点,那么必然这条边的两个端度数大于等于 $2$,因此直接判一下每条边的端点度数就好了。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define x(p) (p.first)
#define y(p) (p.second)
const int maxn=2e5+10;
const int maxm=3e5+10;

int n,m;
int d[maxn];
pii e[maxm];

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>x(e[i])>>y(e[i]);
        d[x(e[i])]++, d[y(e[i])]++;
    }

    bool ok=1;
    for(int i=1;i<=n;i++) ok&=(d[i]>0);
    if(!ok) {cout<<"No\n"; return 0;}
    for(int i=1;i<=m;i++) if(d[x(e[i])]>1 && d[y(e[i])]>1) {ok=0; break;}
    if(ok) cout<<"Yes\n";
    else cout<<"No\n";
}

PS.线段树什么的,只能当做练手了qwq

猜你喜欢

转载自www.cnblogs.com/dilthey/p/10383836.html