专栏文章

题解:CF2137G Cry Me a River

CF2137G题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minpk6b8
此快照首次捕获于
2025/12/02 06:15
3 个月前
此快照最后确认于
2025/12/02 06:15
3 个月前
查看原文
https://codeforces.com/contest/2137/problem/G
这题是一道明显的 DAG\text{DAG} 加上博弈题,注意一开始我们就要从儿子节点向父亲节点连边,因为题目要求我们采用最优的策略如何到达某个节点,我们就要从后往前面去推。
我们定义 dp0/1,idp_{0/1,i} 表示在当前在节点 ii,轮到 Cry/River,当前局面下先手是否有必胜策略。
因为 Cry 获胜的条件是到达一个无出边的节点,所以我们要记录出边度数,用 dud_u 表示。
我们使用拓扑排序的思路,对于每一次询问 uu,将把 (0,u)(0,u)(1,u)(1,u) 加进队列中, 对于每一次更新,如果 (0,v)(0,v),则直接加入,但如果是 (1,v)(1,v) 我们需要考虑是否还有出边,因为题目中要求我们 Cry 获胜条件的限制。
CPP
#include<bits/stdc++.h>
#define int long long
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N=200010;
int n,m,Q;
int dp[2][N];
int d[N];
vector<int>V[N];
void solve(){
    int n,m,Q; 
    cin>>n>>m>>Q;
    rep(i,1,n){
        d[i]=dp[0][i]=dp[1][i]=0;
        V[i].clear();
    }
    rep(i,1,m){
        int u,v; cin>>u>>v;
        V[v].push_back(u);
        ++d[u];
    }
    for(;Q;--Q){
        int op,x;
        cin>>op>>x;
        if(op==2) cout<<(dp[1][x]?"NO":"YES")<<'\n';
        else{
            queue<pair<bool,int>>q;
            q.push({1,x}); q.push({0,x});
            for(;!q.empty();){
                bool f=q.front().first;
                int u=q.front().second; q.pop();
                if(dp[f][u]) continue;
                dp[f][u]=1;
                for(auto v:V[u]){
                    if(f==1){
                        q.push({0,v});
                    }else{
                        --d[v];
                        if(d[v]==0){
                            q.push({1,v});
                        }
                    }
                }
            }
        }
    }
}
signed main(){
    int T; cin>>T;
    for(;T;--T) solve();
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...