P11812 [PA 2015] 精确打击 / Kontrmanifestacja
感觉这题并不困难啊。
首先,我们发现这题本质上是在求所有环的交点。
应该可以容易的想到先找出一个主环(至少我很容易就想到了)。
然后我们需要特判一下,如果没环输出 NIE,如果找出一个主环之后,去掉这个环,整个图中还有其他环,那么答案是 0。
接下来这题就一定有解了。
考虑如何求多个环的交点,交集并不好做,考虑把可以不交的点都去掉。
我们对主环上的点重编号成
那么我们设
此处只考虑
我们同样设
此处只考虑
-
- 反之,没有影响。
正确性应该是显然的。
你考虑怎么求这个东西,可以直接上正反图,跑一下拓扑排序,当然主环上的点会比较特殊。
然后一段区间不能选,可以用差分维护,不能选就区间
所以最后求一遍前缀和,值为
按顺序输出即可。
个人认为这题代码难度大于思维难度。
:::success[code]
#include <bits/stdc++.h>
using namespace std;
inline int read(){
int x=0;
char c=getchar();
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar()) x=(x<<3)+(x<<1)+(c^48);
return x;
}
const int N=1e6+10;
int ans,n,m,cnt,head[N],to[N],nxt[N],fhead[N],fto[N],fnxt[N];
void add(int u,int v){
++cnt;
to[cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
fto[cnt]=u,fnxt[cnt]=fhead[v],fhead[v]=cnt;
return ;
}
int top,vis[N],lst[N],stk[N],stkpos[N];
int tot,cycle[N],pos[N],oncycle[N],iscycle[N];
bool dfs(int x){
vis[x]=1,stk[++top]=x,stkpos[x]=top;
for(int e=head[x];e;e=nxt[e]){
int y=to[e];
if(!vis[y]){
lst[y]=e;
if(dfs(y)) return 1;
}
else if(vis[y]==1){
for(int i=stkpos[y];i<=top;i++){
cycle[++tot]=stk[i],pos[stk[i]]=tot,oncycle[stk[i]]=1;
if(i>stkpos[y]) iscycle[lst[stk[i]]]=1;
}
iscycle[e]=1;
return 1;
}
}
vis[x]=2,stkpos[x]=0,top--;
return 0;
}
int deg[N],q[N];
bool check(){
for(int i=1;i<=n;i++){
if(oncycle[i]) continue;
for(int e=head[i];e;e=nxt[e])
if(!oncycle[to[e]]) deg[to[e]]++;
}
int L=1,R=0,num=0;
for(int i=1;i<=n;i++) if(!oncycle[i]&&!deg[i]) q[++R]=i;
while(L<=R){
int x=q[L++];
num++;
for(int e=head[x];e;e=nxt[e])
if(!oncycle[to[e]]&&!(--deg[to[e]])) q[++R]=to[e];
}
return num!=n-tot;
}
int d[N];
int l[N],r[N],cl[N],cr[N];
void work1(){
memset(deg,0,sizeof deg);
for(int i=1;i<=n;i++)
for(int e=fhead[i];e;e=fnxt[e])
if(!iscycle[e]&&!oncycle[fto[e]]) deg[fto[e]]++;
for(int i=1;i<=tot;i++) l[cycle[i]]=r[cycle[i]]=i;
int L=1,R=0;
for(int i=1;i<=n;i++) if(!deg[i]) q[++R]=i;
while(L<=R){
int x=q[L++];
for(int e=fhead[x];e;e=fnxt[e]){
if(iscycle[e]) continue;
int y=fto[e];
if(oncycle[y]){
if(l[x]){
if(!cl[y]) cl[y]=l[x],cr[y]=r[x];
else cl[y]=min(cl[y],l[x]),cr[y]=max(cr[y],r[x]);
}
}
else {
if(l[x]){
if(!l[y]) l[y]=l[x],r[y]=r[x];
else l[y]=min(l[x],l[y]),r[y]=max(r[x],r[y]);
}
if(!(--deg[y])) q[++R]=y;
}
}
}
for(int i=1;i<=tot;i++){
int x=cycle[i];
if(!cl[x]) continue;
if(i<cl[x]) d[i+1]++,d[cr[x]]--;
else d[i+1]++;
}
return ;
}
int mx[N],cmx[N];
void work2(){
memset(deg,0,sizeof deg);
for(int i=1;i<=n;i++)
for(int e=head[i];e;e=nxt[e])
if(!iscycle[e]&&!oncycle[to[e]]) deg[to[e]]++;
for(int i=1;i<=tot;i++) mx[cycle[i]]=i;
int L=1,R=0;
for(int i=1;i<=n;i++) if(!deg[i]) q[++R]=i;
while(L<=R){
int x=q[L++];
for(int e=head[x];e;e=nxt[e]){
if(iscycle[e]) continue;
int y=to[e];
if(oncycle[y]) cmx[y]=max(cmx[y],mx[x]);
else {
mx[y]=max(mx[x],mx[y]);
if(!(--deg[y])) q[++R]=y;
}
}
}
for(int i=1;i<=tot;i++){
int x=cycle[i];
if(cmx[x]>=i) d[1]++,d[i]--;
}
return ;
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++) add(read(),read());
bool flag=0;
for(int i=1;i<=n;i++){
if(vis[i]) continue;
if(dfs(i)){
flag=1;
break;
}
}
if(!flag) cout <<"NIE",exit(0);
if(check()) cout <<"0",exit(0);
work1(),work2();
for(int i=1;i<=tot;i++){
d[i]+=d[i-1];
if(!d[i]) ans++;
}
cout <<ans<<"\n";
for(int i=1;i<=n;i++) if(oncycle[i]&&!d[pos[i]]) cout <<i<<" ";
return 0;
}
:::