P11693 [JRKSJ ExR] 构造字符串使得

P11693 [JRKSJ ExR] 构造字符串使得

题目描述

给你一张 \(n\) 个点 \(m\) 条边的无向图。现在有一枚棋子初始在点 \(x\)。双人博弈,先后手轮流移动棋子,每次可以将棋子移动到图上任意一个「与当前棋子所在结点有边直接相连」的结点。保证每个结点都有至少一条边与之相连

有一初值为 \(0\) 的变量 \(v\)每次移动过后,记当前棋子所在结点编号为 \(t\),则将 \(v\) 赋值为 \(\max(v,t)\)。也就是说,\(v\) 的值是棋子移动到过的结点编号最大值且棋子的初始位置 \(x\) 一开始并不计算在内

现在先后手总共移动 \(k\) 次棋子,先手希望最终 \(v\) 尽可能大,后手希望最终 \(v\) 尽可能小。

共有 \(q\) 次询问,每次询问给出 \(x,k\),询问假如从 \(x\) 开始一次共 \(k\) 步的博弈,若双方均采用最优策略,那么最终 \(v\) 的值为多少。

对于所有数据,保证 \(2\le n\le 2\times 10^5\)\(1\le m\le 5\times 10^5\)\(1\le q\le 2\times 10^5\)\(1\le x,k\le n\)

保证给出的图无重边、无自环,保证对于任意点 \(u\) 至少存在一个点 \(v\) 使得 \(u,v\) 之间存在一条边。

Solution:

说句闲话:

比赛场切了这题,嘻嘻
刚写完就被勒令回学校了,不嘻嘻
至于回学校的原因嘛,竟然是校长要表彰我们这种天天请假不上课的 竞赛拿奖的 😄 。

言归正传:

我们不难发现博弈的总步数其实就三种: 一步,两步和三步。一步的做法很显然,对于走两步以上的:我们来考虑一个子问题:假设你现在是第二步时的 player2,你该如何走使得权值最小。

对于子问题:

如果你此时只有一步了,那么你可以直接走向所有与 \(pos_1\) 相连的节点中权值最小的

如果你在此时还有两步及以上,那么无论 p1 在第3步时选了什么,p2 只需要在第 4 步时选回第 2 步的点就好了。
那么显然 p1 一定会选一个在 \(pos_2\) 能一步到达的点中点权最大的来做 \(pos_3\)

所以我们先维护一下每个点的邻居的点权的的最大值 \(w_2\),那么作为 p2 的你会选择在 \(pos_1\) 的所有邻居中 \(max(w_2,pos_2)\) 最小的点来做 \(pos_2\) 。我们将这个子问题的答案记为 \(game\)

那么原问题的解显然就是与初始点 \(pos_0\) 相邻的所有子问题中,\(game\) 的最大值。

Code:

#include<bits/stdc++.h>
const int N=2e5+5;
const int inf=1e9;
using namespace std;
vector<int> E[N];
int w[3][N],ans[3][N],game[N],mx[N];
int n,m,q;
void work()
{
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++)
    {
        w[2][i]=inf;w[1][i]=inf;game[i]=inf;
    }
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        E[x].push_back(y);
        E[y].push_back(x);
        w[0][x]=max(w[0][x],y);w[0][y]=max(w[0][y],x);
        w[1][x]=min(w[1][x],y);w[1][y]=min(w[1][y],x);
        w[2][x]=min(w[2][x],y);w[2][y]=min(w[2][y],x);
    }
    for(int i=1;i<=n;i++)
    {
        w[1][i]=max(w[1][i],i);
        if(w[2][i]==inf)w[2][i]=0;
        ans[0][i]=w[0][i];
    }
    for(int x=1;x<=n;x++)for(auto y : E[x])
    {
        ans[2][x]=max({ans[2][x],w[2][y],y});
        game[x]=min(game[x],max(y,w[0][y]));
        ans[1][x]=max(ans[1][x],w[1][y]);
    }
    for(int x=1;x<=n;x++)for(auto y : E[x])mx[x]=max(mx[x],game[y]);
    for(int i=1;i<=n;i++)ans[2][i]=max(ans[2][i],mx[i]);
    for(int i=1,x,k;i<=q;i++)
    {
        scanf("%d%d",&x,&k);
        k= (k>3 ? 3 : k);
        k--;
        printf("%d\n",ans[k][x]);
    }
}
int main()
{
    //freopen("T1.in","r",stdin);freopen("T1.out","w",stdout);
    work();
    return 0;
}
posted @ 2025-02-19 14:12  liuboom  阅读(14)  评论(0)    收藏  举报