• 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;
    }
    
  • 相关阅读:
    他们在清华的那几年——清华学长语录
    java正则表达非捕获组详解
    VC++ 6.0 快捷键大全
    vs2008的使用
    css的一些基本概念
    VC项目配置基础
    企业该如何规划建设自身的网站
    IT技术人员的薪资到底该如何定?
    高级程序员应该具备什么能力
    软件项目为什么成功率不高
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/10326247.html
Copyright © 2020-2023  润新知