题目描述
她们玩得很开心,但是现在到了她们应当离开的时间了,她们会一个接一个地离开。她们想要以某种顺序离开,使得只要至少还有两头奶牛尚未离开,所有尚未离开的奶牛都还有没有离开的朋友。此外,由于行李寄存的因素,有M对奶牛必须满足奶牛
要比奶牛
先离开。注意奶牛
和奶牛
可能是朋友,也可能不是朋友。
输入描述:
输入的第行包含两个空格分隔的整数
和
。
输入的第行,每行包含两个整数
和
,满足
,表示奶牛
和奶牛
是朋友关系。
输入的第行,每行包含两个整数
和
,满足
,表示奶牛
必须比奶牛
先离开聚会。
输入保证。对于占总分20%的测试数据,保证
。
输出描述:
输出行,每行包含一个整数
,如果奶牛
可以成为最后一头离开的奶牛,则
,否则
。
示例1
5 1
1 2
2 3
3 4
4 5
2 4
0
0
1
1
1
解答
给你一棵个节点的树,每次删去一个叶子节点,直到剩下一个节点
但是有个限制
,表示如果
没被删除,
不能删除
最后输出所有能成为最后一个节点的节点
显而易见,对于每个限制,以为根时
的子树(包括自己)都是不可行点
于是我们可以写出一个支持子树修改和换根数据结构,比如,树链剖分(参见
)
但是单单这个结论是不够的,我们观察一下这组数据
3 2
1 2
2 3
1 3
3 1
0
0
0
0
1
0
因为没有考虑无解情况
那么如何考虑无解情况呢
该题中的无解就是指没有一个点是可行点,那么我们其实只要找出任何一个可行点就可以了
怎么找?
我们将树上的条边连成双向边,将限制里的
连向
一条单向边
那么,我们每次就只能删除入度为的点
因为如果这个点不是叶子节点,入度至少为,如果有被连有向边(被约束),入度也至少为
随便找一个入度为的点删除,接下来将它连向的边都删除(也就是说连向的点入度--),然后如果更新后连向的点的入度为
(不需要每次
统计,只统计这次删除更新的点就行了),加入待定删除点
最后,如果还没有删除个点就无法继续删了(没有入度为
的点了,比如每个点都被互相约束),说明无解,否则有解
这部分代码(为了方便第二种解法,我用了存(
是双向边,
是单向边)):
queue<int>q;
int findroot()
{
while(!q.empty())
{
int x=q.front();
q.pop();
if(!deg[x]/*入度*/)return x;
for(int i=0;i<to[x].size();i++)
{
if(--deg[to[x][i]]==1)
{
q.push(to[x][i]);
}
}
for(int i=0;i<d[x].size();i++)
{
if(--deg[d[x][i]]==1)
{
q.push(d[x][i]);
}
}
}
return 0;
}
这样写的话,时间复杂度为
代码:咕咕咕
但是我们刚刚那个方法显然不够优(太暴力了),虽然足以通过本题,但是如果数据加到
,显然过不了(吧,有松松松真传我也没办法2333)
首先我们要证(kou)明(hu)两个结论:
一,可行点连通
因为每次修改不可行点只是修改子树,并不破坏可行点的连通性,所以成立
二,任意一个可行点作为根,删除每个限制中的的子树,剩下的都是可行点
这个我真不会证,我的想法是将可行点看为树的中间部分,不可行点是树的一些边角,从中间往四周边角扩散不需要考虑从哪里开始,由于可行点连通,所以不需要每次换根
我们将的位置打上标记,以
的返回值(任意一个可行点)为起始点,遇到标记直接
,最后输出答案即可
时间复杂度:
总时间复杂度
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
vector<int>to[100001],d[100001];
queue<int>q;
int n,m,deg[100001];
bool vis[100001],ans[100001];
int findroot()
{
while(!q.empty())
{
int x=q.front();
q.pop();
if(!deg[x])return x;
for(int i=0;i<to[x].size();i++)
{
if(--deg[to[x][i]]==1)
{
q.push(to[x][i]);
}
}
for(int i=0;i<d[x].size();i++)
{
if(--deg[d[x][i]]==1)
{
q.push(d[x][i]);
}
}
}
return 0;
}
void dfs(int x,int f)
{
ans[x]=1;
for(int i=0;i<to[x].size();i++)
{
if(!vis[to[x][i]]&&f!=to[x][i])
{
dfs(to[x][i],x);
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<n;i++)
{
int x,y;
cin>>x>>y;
to[x].push_back(y);
to[y].push_back(x);
deg[x]++;
deg[y]++;
}
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
d[x].push_back(y);
deg[y]++;
vis[x]=1;
}
for(int i=1;i<=n;i++)
{
if(deg[i]==1)q.push(i);
}
int root=findroot();
dfs(root,0);
for(int i=1;i<=n;i++)
{
cout<<ans[i]<<endl;
}
return 0;
}

京公网安备 11010502036488号