首页 > 技术文章 > P5157 [USACO18DEC]The Cow Gathering

tcswuzb 2019-03-28 06:30 原文

题目链接

题意分析

题意

给你一棵树 每一次都会删除一个叶子节点 同时树上存在一些有向边\((a,b)\)

必须满足\(a\)\(b\)之前删除

问每一个节点作为根节点时是否存在合法的删边情况 使得跟、根节点被最后一个删除


换根\(dp\)\(No\)

首先有向边必定形成一个或者多个\(DAG\)

所以先判断是否有环

然后做做这道题 遥远的国度

以当前点作为根节点不合法的情况就是

存在有向边\((a,b)\)满足\(a\)\(b\)的祖先

那么我们对于每一条有向边分开讨论判断那些节点在当前有向边情况下可以成为根节点

同那道题 分情况讨论

1.\(a\)\(b\)的祖先

那么只有\(a\)的子树(不包括\(a\))可以成为根节点

2.\(a\)不是\(b\)的祖先

那么只有\(a\)的子树(包括\(a\))不可以成为根节点

然后我们使用\(dfs\)序实现区间覆盖就可以了

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
#define ll long long
#define inf 0x7fffffff
#define N 500008
#define IL inline
#define M 508611
#define D double
#define ull unsigned long long
#define R register
using namespace std;
template<typename T>IL void read(T &_)
{
    T __=0,___=1;char ____=getchar();
    while(!isdigit(____)) {if(____=='-') ___=0;____=getchar();}
    while(isdigit(____)) {__=(__<<1)+(__<<3)+____-'0';____=getchar();}
    _=___ ? __:-__;
}
/*-------------OI使我快乐-------------*/
int n,m,tot,cnt,top,all;
int to[M],nex[M],head[M],ans[M];
int dep[M],fath[M][20],siz[M];
int dfn[M],wt[M],tre[M],in[M];
int dfnn[M],low[M],sta[M];
bool vis[M];
vector<int> G[M];
bool flag;
IL void add_edge(int x,int y)
{;to[++tot]=y;nex[tot]=head[x];head[x]=tot;}
IL void add(int x,int y)
{for(;x<=n;x+=x&-x) tre[x]+=y;}
IL int qury(int x)
{int res=0;for(;x;x-=x&-x) res+=tre[x];return res;}
IL void dfs(int now,int fat,int deep)
{
    dep[now]=deep;fath[now][0]=fat;dfn[now]=++cnt;wt[cnt]=now;siz[now]=1;
    for(R int i=1;i<=19;++i) fath[now][i]=fath[fath[now][i-1]][i-1];
    for(R int i=head[now];i;i=nex[i])
    {
        int v=to[i];
        if(v==fat) continue;
        dfs(v,now,deep+1);
        siz[now]+=siz[v];
    }
}
IL int LCA(int nowx,int nowy)
{
    if(dep[nowx]<dep[nowy]) swap(nowx,nowy);
    for(R int i=19;i>=0;--i)
    if(dep[fath[nowx][i]]>=dep[nowy]) nowx=fath[nowx][i];
    if(nowx==nowy) return nowx;
    for(R int i=19;i>=0;--i)
    if(fath[nowx][i]!=fath[nowy][i]) 
    nowx=fath[nowx][i],nowy=fath[nowy][i];
    return fath[nowx][0];
}
IL void update(int x,int y)
{
    if(x>y) return;
    add(x,1);add(y+1,-1);
}
IL void Tarjan(int now)
{
    dfnn[now]=low[now]=++cnt;
    vis[now]=1;sta[++top]=now;
    for(R int i=0;i<(int)G[now].size();++i)
    {
        int v=G[now][i];
        if(!dfnn[v]) Tarjan(v),low[now]=min(low[now],low[v]);
        else if(vis[v]) low[now]=min(low[now],dfnn[v]);
    }
    if(low[now]==dfnn[now])
    {
        all=0;
        while(sta[top+1]!=now)
        {
            ++all;
            vis[sta[top--]]=0;
        }
        if(all>1) flag=1;
    }
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
    read(n);read(m);
//	puts("0");return 0;
    for(R int i=1,x,y;i<n;++i)
    {
        read(x);read(y);
        add_edge(x,y);add_edge(y,x);
    }
    dfs(1,0,1);
//	for(R int i=1;i<=n;++i) printf("%d%c",siz[i],(i==n ? '\n':' '));
    for(R int i=1,x,y;i<=m;++i)
    {
        read(x);read(y);
        G[x].push_back(y);
        int lca=LCA(x,y);
//		printf("lca=%d\n",lca);
        if(lca==x)
        {
//			puts("now cdy");
            int now=y;
            for(R int i=19;i>=0;--i)
            if(fath[now][i]&&dep[fath[now][i]]>dep[x]) now=fath[now][i];
//			printf("now at %d\n",now);
//			printf("(%d , %d)\n",dfn[now],dfn[now]+siz[now]-1);
            update(dfn[now],dfn[now]+siz[now]-1);
        }
        else
        {
//			puts("now wzy");
            update(1,dfn[x]-1);update(dfn[x]+siz[x],n);
        }
    }
    for(R int i=n;i;--i) if(!dfnn[i]) Tarjan(i);
    if(flag)
    for(R int i=1;i<=n;++i) puts("0");
//	for(R int i=1;i<=n;++i) printf("%d\n",qury(1))
    else 
    for(R int i=1;i<=n;++i) printf("%d\n",qury(dfn[i])==m);
//	fclose(stdin);
//	fclose(stdout);
    return 0;
}

HEOI 2019 RP++

推荐阅读