P5157 [USACO18DEC]The Cow Gathering

Posted creed-qwq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P5157 [USACO18DEC]The Cow Gathering相关的知识,希望对你有一定的参考价值。

首先考虑怎么check一个点是否能被最后一个删除。
可以这么建图,以这个点建有根树,边全部向上指,再加上剩下的有向边。
很明显,这里的一条边的定义就变成了只有删去这个点,才可以删去它指向的点。
因此,只需要建n次图暴力判断是否有环即可。
这样做是n^2的。
考虑加入一条边后,会产生什么影响。
发现这条边会导致一些点答案直接被钦定为零(这些点满足以它们为根一定会存在环)
设边为u---->v
具体分析一下,这些点是所有以v为根建有根树后,u子树内的所有点。
这个可以通过类似换根的分类讨论的方法来找到这些点,它们构成了几段(O(1)级别)区间。
直接差分钦定它们答案为0即可。
然而这样做是有bug的。
考虑这样一个图
技术分享图片
按照上述方法只能判断出2,3,4,5不合法。
事实上因为在上述方法中,只考虑了每条边自己单一的影响,而没有考虑它们组合起来的影响。
胡乱分析发现,它们组合起来产生的影响要么是没影响,要么就是所有点都无法被留到最后一个删除。
这样的话,只需要特判一下是否整个图的无法被留到最后一个删除即可。
可以用类似拓扑排序的方法来判断。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdlib>
#include<algorithm>
#define N 220000
#define L 200000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline int read()
{
    char ch=0;
    int x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch==‘-‘)flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();}
    return x*flag;
}
struct edge{int to,nxt;}e[N*2],E[N*2];
int num,head[N],NUM,HEAD[N];
inline void add(int x,int y){e[++num]=(edge){y,head[x]};head[x]=num;}
inline void ADD(int X,int Y){E[++NUM]=(edge){Y,HEAD[X]};HEAD[X]=NUM;}
queue<int>q;
bool vis[N];
int times,c[N],sz[N],deg[N],deg_[N],dep[N],dfn[N],nxt[N][25];
void dfs(int x,int fa)
{
    sz[x]=1;dfn[x]=++times;dep[x]=dep[fa]+1;
    for(int i=head[x];i!=-1;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa)continue;
        dfs(to,x);sz[x]+=sz[to];nxt[to][0]=x;
    }
}
int get(int x,int k){for(int i=0;i<=20;i++)if(1<<i&k)x=nxt[x][i];return x;}
int main()
{
    num=NUM=-1;memset(head,-1,sizeof(head));memset(HEAD,-1,sizeof(HEAD));
    int n=read(),m=read(),tot=0;
    for(int i=1;i<n;i++){int x=read(),y=read();add(x,y);add(y,x);deg[x]++;deg[y]++;}
    dfs(1,1);
    for(int k=1;k<=20;k++)for(int i=1;i<=n;i++)nxt[i][k]=nxt[nxt[i][k-1]][k-1];
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        ADD(x,y);deg_[y]++;
        int l=dfn[x],r=dfn[x]+sz[x]-1;
        if(l<=dfn[y]&&dfn[y]<=r)
        {
            int to=get(y,dep[y]-dep[x]-1);
            int pl=dfn[to],pr=dfn[to]+sz[to]-1;
            c[pl]--;c[pr+1]++;c[1]++;c[n+1]--;
        }
        else c[l]++,c[r+1]--;
    }
    for(int i=1;i<=n;i++)if(deg[i]==1&&!deg_[i])q.push(i);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        if(vis[x])continue;vis[x]=true;tot++;
        for(int i=head[x];i!=-1;i=e[i].nxt){int to=e[i].to;deg[x]--;deg[to]--;}
        for(int i=HEAD[x];i!=-1;i=E[i].nxt){int to=E[i].to;deg_[to]--;}
        for(int i=head[x];i!=-1;i=e[i].nxt){int to=e[i].to;if(deg[to]==1&&!deg_[to])q.push(to);}
        for(int i=HEAD[x];i!=-1;i=E[i].nxt){int to=E[i].to;if(deg[to]==1&&!deg_[to])q.push(to);}
    }
    if(tot<n){for(int i=1;i<=n;i++)printf("0
");return 0;}
    for(int i=1;i<=n;i++)c[i]+=c[i-1];
    for(int i=1;i<=n;i++)printf("%d
",c[dfn[i]]?0:1);
    return 0;
}


















以上是关于P5157 [USACO18DEC]The Cow Gathering的主要内容,如果未能解决你的问题,请参考以下文章

P2966 [USACO09DEC]牛收费路径Cow Toll Paths

bzoj4745: [Usaco2016 Dec]Cow Checklist

[BZOJ] 1648: [Usaco2006 Dec]Cow Picnic 奶牛野餐

[BZOJ1648][Usaco2006 Dec]Cow Picnic 奶牛野餐

Bzoj3893 [Usaco2014 Dec]Cow Jog

洛谷——P2853 [USACO06DEC]牛的野餐Cow Picnic