csps 星战题解
更好的体验
首先可以观察出一个性质,只要每个点的出度都是 1,这个图就是一个内向奇环树,也就是说只要每个点出度为 1,那么该情况就是合法的。然后考虑怎么动态维护每个点的出度。
这里我们使用一个哈希,用一个值记录当前每个点的出度大小为多少,当这个值和“每个点出度为 1”这个状态的值一样的时候就是合法的值了。设出度为
当一条边
另:由于本蒟蒻恶臭习惯,喜欢把出边和入边反过来写,所以代码里面
#include<iostream>
#include<cstdio>
#include<cstring>
typedef long long ll;
using namespace std;
const ll N=6e5,p0=23333,mod1=998244353,mod2=1e9+7;
ll n,m,in[N],qu;
struct Pair{
ll x,y;
Pair operator *(const ll&tmp )const{
Pair c;
c.x=x*tmp%mod1,c.y=y*tmp%mod2;
return c;
}
Pair operator +(const Pair&tmp )const{
Pair c;
c.x=(x+tmp.x)%mod1,c.y=(y+tmp.y)%mod2;
return c;
}
Pair operator -(const Pair&tmp )const{
Pair c;
c.x=(x-tmp.x+mod1)%mod1,c.y=(y-tmp.y+mod2)%mod2;
return c;
}
void clear(){x=0,y=0;}
}p[N],sam,cur,pas[N],ou[N];
int main(){
cin>>n>>m;
p[0].x=p[0].y=1;
for(ll i=1;i<=n;i++)p[i]=p[i-1]*p0;
for(ll i=1;i<=m;i++){
ll a1,a2;
scanf("%lld%lld",&a1,&a2);
in[a1]++,ou[a2]=ou[a2]+p[a1];
}
for(ll i=1;i<=n;i++)sam=sam+p[i];
for(ll i=1;i<=n;i++)
cur=cur+(Pair){p[i].x*in[i]%mod1,p[i].y*in[i]%mod2};
cin>>qu;
for(ll i=1;i<=qu;i++){
ll a1,a2,a3;
scanf("%lld",&a1);
if(a1==1){
scanf("%lld%lld",&a2,&a3);
cur=cur-p[a2];
pas[a3]=pas[a3]+p[a2];
}
if(a1==2){
scanf("%lld",&a2);
cur=cur-ou[a2];
cur=cur+pas[a2];
pas[a2]=ou[a2];
}
if(a1==3){
scanf("%lld%lld",&a2,&a3);
cur=cur+p[a2];
pas[a3]=pas[a3]-p[a2];
}
if(a1==4){
scanf("%lld",&a2);
cur=cur+pas[a2];
pas[a2].clear();
}
if(cur.x==sam.x&&cur.y==sam.y)printf("YES\n");
else printf("NO\n");
}
}