P8819 CSP 2022 S T3 星战
简要题意
有一个
- 操作
\tt1 :让一条可用的边变得不可用 - 操作
\tt2 :让一个点的所有入边中,可用的变得不可用 - 操作
\tt3 :让一条不可用边变得重新可用 - 操作
\tt4 :让一个点的所有入边中,不可用的变得可用
每次操作之后,如果同时满足
- 条件
\tt1 :从每个点开始都可以无限的沿着可用边(有向)走下去。 - 条件
\tt2 :每个点只有一条出边可用
就输出 YES,否则输出 NO。
60 分的部分分
暴力太简单不讲。
首先我们分析条件
而内向基环树是一个环上挂着若干棵儿子向父亲连有向边的树,每个点可以先沿着有向边走上环,然后在环上无限走。所以必然满足条件
那么最后只需要判断条件
我们维护一个出度数组。发现操作
然后发现如果只有操作
虽然笔者的思考止步于此,但是我拿的分可不止
于是靠着官方数据用脚造以及官方少爷机的神速,
评测链接。
正解
对条件
我们对每个点定义一个权值,它是一个随机数。
然后对于每一个点
然后操作
操作
在更改的过程中动态维护
如果
总结
用到了哈希的思想,正解写起来比
哈希思维难度大于部分分?但是想下来其实挺简单的。果然自己的思维还是有不足之处。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int n,m,q,a[N];
long long to[N],sum[N],tot,ans;
int main(){
mt19937 rnd(time(0));
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i) ans += (a[i] = rnd());
for(int i = 1,u,v;i <= m;++i)
scanf("%d%d",&u,&v),to[v] += a[u],sum[v] = to[v],tot += a[u];
scanf("%d",&q);
for(int i = 1,t,u,v;i <= q;++i){
scanf("%d%d",&t,&u);
if(t == 1) scanf("%d",&v),to[v] -= a[u],tot -= a[u];
if(t == 2) tot -= to[u],to[u] = 0;
if(t == 3) scanf("%d",&v),to[v] += a[u],tot += a[u];
if(t == 4) tot += sum[u] - to[u],to[u] = sum[u];
puts(tot == ans ? "YES" : "NO");
}
return 0;
}