首页 > 其他分享 >[SDOI2010] 大陆争霸 题解

[SDOI2010] 大陆争霸 题解

时间:2023-12-24 22:23:49浏览次数:36  
标签:node 争霸 int 题解 into pos SDOI2010 arrive dis

[题目传送门](https://www.luogu.com.cn/problem/P2446)

# 解法
由题可知,一个城市$u$保护城市$v$,所以建一条边$u \to v$表示城市$u$保护城市$v$,因为题目说保证有解,所以建的图一定是一个**有向无环图$DAG$** 。再在此基础上求出最短路径。

具体过程为设$dis_u$表示实际到达(攻破)$u$的最短时间,$arrive_u$表示到达$u$的时间(注意$arrive_u  \neq dis_u$,而是$arrive_u \le dis_u$)。然后考虑怎么转移,我们发现$arrive_u$只会影响一个值就是$dis_u$,而$dis_u$能影响其他节点的$arrive$和$dis$值。

所以先考虑$arrive_u$的转移:

- $arrive_u=\min(dis_v,arrive_u)$,其中$v$为与$u$相邻的节点。显然$arrive_v$不能更新$dis_u$,因为$arrive_v$表示只是到达了$v$点,但可能还没有进入$v$点,所以不能这样更新。

然后再来考虑$dis_u$的转移:

- $dis_u=\max(arrive_u,dis_v)$,$v$表示保护$u$的节点编号。如果$arrive_u \le dis_v$表明到达$u$点可能还没有进入的最早时间比攻破$v$点的时间早,那么显然此时$dis_u$应该由$dis_v$决定。如果$arrive_u \ge dis_v$表明到达$u$点可能还没有进入的最早时间比攻破$v$点的时间晚,而因为此时保护$u$点的节点都被攻破了,所以由$arrive_u$来决定,即$dis_u=arrive_u$。

转移过想出来了,于是现在考虑用怎样的顺序能正确更新$dis_u$与$arrive_u$。我们发现上述过程与$dijkstra$算法的过程很相似,如果我们也每次取出$dis$值最小的点来进行更新就行。( **为什么可以直接取出$dis$值最小的点进行更新?因为类似于$djikstra$的证明一定不存在另外的路径使得$dis$值再变小。** )于是我们就可以用$dijkstra+topo$来实现啦。

# $Code$

```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=3050,M=70050;
long long dis[N],arrive[N],into[N];
int n,m;
int head[N],to[M],w[M],nxt[M],cnt,in[N];
bool vis[N];
vector<int> g[N];
void add(int u,int v,int f)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    w[cnt]=f;
    head[u]=cnt;
}
struct node{
    long long val;int pos;
    bool operator >(const node &x)const{
        return val>x.val;
    }
};
void dij(int s)
{
    for(int i=1;i<=n;i++)dis[i]=arrive[i]=1e18;
    dis[s]=into[s]=arrive[s]=0;
    priority_queue<node,vector<node>,greater<node> >q;
    q.push(node{0,s});
    while(!q.empty())
    {
        node t=q.top();q.pop();
        if(vis[t.pos])continue;
//        cout<<t.pos<<endl;
        vis[t.pos]=1;
        for(int i=head[t.pos];i;i=nxt[i])
        {
            int v=to[i];
            if(arrive[v]>dis[t.pos]+w[i])
            {
                arrive[v]=dis[t.pos]+w[i];
                if(!in[v])
                {
                    dis[v]=max(into[v],arrive[v]);
                    q.push(node{dis[v],v});
//                    cout<<v<<endl;
                }
            }
        }
        for(auto v:g[t.pos])
        {
            in[v]--;
            into[v]=max(into[v],dis[t.pos]);
            if(!in[v])
            {
                dis[v]=max(arrive[v],into[v]);
                q.push(node{dis[v],v});
            }
        }
    }
    return;
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1,u,v,w;i<=m;i++)
    {
        scanf("%d %d %d",&u,&v,&w);
        add(u,v,w);
    }
    for(int i=1;i<=n;i++)
    {
        int x,v;
        scanf("%d",&x);
        while(x--)
        {
            scanf("%d",&v);
            g[v].push_back(i);
            in[i]++;
        }
    }
    dij(1);
    printf("%lld\n",dis[n]);
    return 0;
}
```

标签:node,争霸,int,题解,into,pos,SDOI2010,arrive,dis
From: https://www.cnblogs.com/CQWYB/p/17924960.html

相关文章

  • 「HCOI-R1」报名人数 题解
    博客园。我们会发现,\(2\)和\(3\)的火柴个数是一样的,\(9\)和\(0\)的火柴个数是一样的。所以只有在\(12\)到\(13\)这样是合法的,自己推一下可以知道,最多只有连续两个。而在\(l\)到\(r\)的长度大于\(9\)的时候可以直接输出\(2\)。剩下的情况直接暴力枚举即可。#......
  • CF contest 1909 Pinely Round 3 (Div. 1 + Div. 2) 题解(Vanilla的掉分赛)
    CFcontest1909PinelyRound3(Div.1+Div.2)Vanilla的掉分赛绪言PinelyRound3(Div.1+Div.2)-Codeforces\[\color{purple}\large\textbf{世界上只有一种真正的英雄主义,}\]\[\color{red}\large\textbf{就是认清了生活的真相后还依然热爱它。}\]\[\color{gray}......
  • AtCoder Beginner Contest 334题解
    ⭐AtCoderBeginnerContest334前言:比赛题目链接--按照惯例只写了主要部分的代码--特别说明:Rust有一个竞赛用的输入库,并且写ABC是可以用的,但是平时写洛谷是用不了的,所以我自己写了一个cin(),凑活能用,代码见下:读输入函数fncin()->String{letmutinput=String......
  • 【题解】洛谷P1496 火烧赤壁 (离散化)
    P1496火烧赤壁-洛谷|计算机科学教育新生态(luogu.com.cn)我们首先先看数据,n<=20000,数据不多,但是范围大(-10^9<=Ai,Bi<=10^9),这时,就可以用离散化了。但是在这里我们会遇到区间重合的问题(也可以使用区间合并),如下图本题的题意是让我们求出燃烧位置的长度之和。区间重合时只......
  • [ABC265F] Manhattan Cafe 题解
    [ABC265F]ManhattanCafe题解思路解析很有思维难度的一道题。思路是dp,\(f[i][j][k]\)表示已经计算了\(i\)维,距离点\(p\)的距离为\(j\),距离点\(q\)的距离为\(k\)时的整点\(r\)个数,由此可见我们的每一维都可以从上一维推出来,也即\(f[i][j][k]\)可以由\(f[i-1][j......
  • ABC334 全套题解
    A-ChristmasPresent简单题。voidslv(){ inta=Read<int>(),b=Read<int>(); if(a>b)Puts("Bat"); elsePuts("Glove"); return;}B-ChristmasTrees也是简单题。constexpri128INF=-1e18;i128a,m,l,r;voidslv(......
  • 题解 ABC334G【Christmas Color Grid 2】
    先求出初始时绿连通块数量。将一个绿色格子染成红色,会改变绿连通块数量,当且仅当这个绿色格子是孤点或割点。如果是孤点,会使得绿连通块数量减少一;如果是割点,会使得绿连通块数量增加它所在的点双数量减一。根据上述规则可以求出每个绿色格子染红后的绿连通块数量,求平均值即可。时......
  • 题解 ABC334F【Christmas Present 2】
    设\(f_i\)表示假设只有编号为\(1\simi\)的点,此时的答案。\(f_n\)即为所求。显然有:\[f_i=\min\limits_{i-k\lej<i}\{f_j+dis(s\toj+1\toj+2\to\cdots\toi)\}+dis(i\tos)\]当\(i\toi+1\)时,大括号内部全局增加\(dis(i\toi+1)\),可以全局打标记后单调队列维护。......
  • 题解 ABC334E【Christmas Color Grid 1】
    先求出初始时绿连通块数量。枚举每个红色格子,将其染成绿色本应增加一个绿连通块,但是它每与一个绿连通块相邻,就又会减少一个绿连通块。根据上述规则可以求出每个红色格子染绿后的绿连通块数量,求平均值即可。时间复杂度\(O(nm)\)。//Problem:E-ChristmasColorGrid1//Co......
  • 检查Windows更新问题解决
    在任务栏搜索框输入cmd,点击右侧的“以管理员身份运行”,打开后输入:(建议复制粘贴,防止输入有误出现错误提示等请忽略*)SCconfigwuauservstart=auto回车(Enter按键)SCconfigbitsstart=auto回车(Enter按键)SCconfigcryptsvcstart=auto回车(Enter按键)SCconfigtrustedin......