码迷,mamicode.com
首页 > 其他好文 > 详细

P5157 [USACO18DEC]The Cow Gathering

时间:2019-03-28 09:43:55      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:out   节点   stdout   cpp   区间覆盖   return   bool   span   pen   

题目链接

题意分析

题意

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

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

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


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

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

所以先判断是否有环

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

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

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

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

同那道题 分情况讨论

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

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

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

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

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

CODE:

/*-------------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++

P5157 [USACO18DEC]The Cow Gathering

标签:out   节点   stdout   cpp   区间覆盖   return   bool   span   pen   

原文地址:https://www.cnblogs.com/LovToLZX/p/10612520.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!