首页 > 其他分享 >[ABC232G] Modulo Shortest Path (优化建图)

[ABC232G] Modulo Shortest Path (优化建图)

时间:2024-04-19 18:13:20浏览次数:24  
标签:Modulo int ll 建图 内点 ABC232G 外点 mod dis

链接:https://www.luogu.com.cn/problem/AT_abc232_g

暴力的做法肯定不行,这道题要用到一个比较经典的拆点操作:把一个点拆成内点和外点。在接下来的分析中会慢慢介绍。

由于题目每次连的边都是单向边,那要考虑的问题是:比如说现在要从1走到3,怎么走才能与暴力建边等价。

先不考虑取模这个条件。假如说我一开始就是暴力建边,那么比如从1走到3的路径长度就是(a[1]+b[3])。那么我们可以把一个点拆成一个内点和外点,其中外点向内点链接一条长度为0的边,内点向外点链接一条 b[1]+a[i] 的边,然后外点向下一个外点链接一条 b[i+1]-b[i] 的边。

为什么要这么连呢?我们考虑题目中要求的是求1到n的最短路。那么从1号点出发时,先是从内点走向外点,随后一直走外点直到目的地,对应的边权该抵消的抵消该相加的相加。到最后达到目的地的时候,累加起来的结果就是我们想要的边权。比如说从1走到3,那么路径上的所有边权 就是 b[1]+a[1]+b[2]-b[1]+b[3]-b[2]+0=a[1]+b[3]

现在再来考虑取模这个条件。我们观察数据范围可以发现 a[i]+b[i] 不可能超过 2*m ,那么也就是说可以直接把取模这个条件转化成 (a[i]+b[i]-m). 我们可以将b数组先进行排序,从小到大与进行连边。我们二分查找出第一个需要取模操作的点 k,连一条从i的内点指向k的外点的一条长度为 (b[k]-a[i]-m) 的边即可。
因为这个k相当于一个分界点,在这个分界点只需要出现一次 -m,在后面的累加过程中这个 -m 是不会被消掉的,其他的累加抵消操作和上面一致。

连好了边,跑一次Dijkstra即可。理解不了,可以画一张图,然后看一看是怎么抵消的就行。然后要理解Dij跑最短路的原理就会知道到这个点到答案怎么更新,然后就可以分析每条边有一种各司其职的感觉,从内点到外点的边有些在更新答案的时候是没有用的,不会影响到最短路统计。

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
#define mp make_pair
#define ull unsigned long long
#define all(x) x.begin(), x.end()
//__builtin_count()
typedef array<int,2> pr;
const unsigned int mask =  (chrono::steady_clock::now().time_since_epoch().count());
inline int gcd(int a, int b){return b == 0 ? a : gcd(b, a % b);}//gcd(a,b)=gcd(a,b-a)(b>a);
inline int lcm(int a, int b){return a / gcd(a, b) * b;}//lcm(n,m)=n*m/gcd(n,m)
const ll mod = 998244353;
const int inv2 = (mod+1)/2;
#define lson rt<<1
#define rson rt<<1|1
int addmod(int &x, int y) {x = (x + y >= mod ? x + y - mod : x + y);return 1;}
ll qpow(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll inv(int x){return qpow(x,mod-2);}
inline void read(__int128 &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
int o[200010],on;
inline void output(__int128 x)
{
    on=0;
    while(x) o[++on]=x%10,x/=10;
    for(int i=on;i>=1;i--) cout<<o[i];
}

const int maxn = 5e5+10;
struct node{
    int a,b,id;
    bool operator < (const node &k) const{
        return b<k.b;
    }
}a[maxn];
struct dian{
    int v,w;
    bool operator < (const dian &k) const{
        return w>k.w;
    }
}g[maxn];
int n,m;
int b[maxn],dis[maxn],vis[maxn];
vector<pr> vec[maxn];
void dij(int st)
{
    priority_queue<dian> que;
    memset(dis,0x3f,sizeof(dis));
    que.push({st,dis[st]});
    dis[st]=0;
    while(!que.empty())
    {
        auto x=que.top();
        que.pop();
        if(vis[x.v]) continue;
        vis[x.v]=1;
        for(auto to:vec[x.v])
        {
            if(dis[to[0]]>dis[x.v]+to[1])
            {
                dis[to[0]]=dis[x.v]+to[1];
                que.push({to[0],dis[to[0]]});
            }
        }
    }
}   
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].a;
        a[i].id=i;
    }
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].b;
    }
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
    {
        b[i]=a[i].b;
    }
    int st,ed;
    for(int i=1;i<=n;i++)
    {
        if(a[i].id==1)
        {
            st=i;
        }
        else if(a[i].id==n) ed=i;
        vec[i+n].push_back({i,0});
        vec[i].push_back({n+1,b[1]+a[i].a});
        int k=lower_bound(b+1,b+1+n,m-a[i].a)-b;
        if(k<=n)
        {
            vec[i].push_back({k+n,b[k]+a[i].a-m});
        }
    }
    for(int i=1;i<n;i++)
    {
        vec[i+n].push_back({i+n+1,b[i+1]-b[i]});
    }
    dij(st);
    cout<<dis[ed]<<'\n';
    return 0;
}

标签:Modulo,int,ll,建图,内点,ABC232G,外点,mod,dis
From: https://www.cnblogs.com/captainfly/p/18146565

相关文章

  • 线段树优化建图学习笔记
    关于线段树优化建图对于存在一些单点连向区间或区间连向单点的边,且直接暴力连边会爆炸的题目,就可以考虑使用线段树优化建图。边数量的规模将会是\(n\logn+a\)。例题题目链接。从\(s\)到\(t\)的最短路就是模板。如果暴力建边,最坏情况下需要建的边在\(n^2\)级别,显然是......
  • 使用又拍云极速搭建图床
    前言某天在群里摸......
  • 3/28 线段树优化建图
    (1)CF786BLegacy有一张\(n\)个节点和若干条边。边用\(q\)条信息表示:1vuw表示有一条连接\(v\tou\)的有向边,边权为\(w\);2vlrw表示对于所有\(u\in[l,r]\),都有一条连接\(v\tou\)的有向边,边权为\(w\);3vlrw表示对于所有\(u\in[l,r]\),都有......
  • CAXA装配图中单击序号,有图开图,无图建图
    1//点序号,有图开图,无图建图2voidcmdOpenDrawFromSN()3{4//单击一个序号,炸开,找数字,成功后删除炸开的实体组5crx_nameen;6crx_pointpt;7CRxGePoint3dpB;//单行文字的基点8CRxGePoint3dpS;//选择实体时的单击点9......
  • Atcoder ABC245H Product Modulo 2
    发现这个\(m\)很大,且这个式子是\(\times\)。一个想法是拆成\(m=\prod{p_i}^{e_i}(p_i\in\mathbb{P})\)然后对于\(M=p_i^{e_i}\)依次考虑\(b_i=a_i\bmodM\)和\(N=n\bmodM\)。根据\(\text{CRT}\),对于任意一个\(M\)得到的不同的\(b_i\)对于最后的\(a_i......
  • 自动驾驶建图--道路边缘生成方案探讨
    自动驾驶建图--道路边缘生成方案探讨一、背景对于自动驾驶来说,建图是必不可少的,目前主流厂商技术都在从HD到"无图"进行过渡筹备中,不过想要最终实现真正的"无图"还是有很长的一段路要走。对于建图来说,包含了很多的道路元素,车道线,停止线,斑马线,导流属性,道路边缘以及中心线(包含引......
  • Navigation System(djkstra,反向建图,思维)
    ThemapofBertowncanberepresentedasasetof nn intersections,numberedfrom 11 to nn andconnectedby mm one-wayroads.Itispossibletomovealongtheroadsfromanyintersectiontoanyotherintersection.Thelengthofsomepathfromonei......
  • 搭建图床-切换本站图片至自建服务
    家宽环境搭建兰空图床实践过程记录分享朗读全文Yourbrowserdoesnotsupporttheaudioelement.有什么用/怎么用自建图床,自用的情况下暂时是够用的访问:CarlNotes图床登录后台管理图床中的图片内容等操作相关内容实现方法Docker搭建LskyPro图床应用dockerpull......
  • 1.1.3.4 最小割之建图实战、费用流基本概念
    1.1.3.4最小割之建图实战、费用流基本概念最小割之建图实战381.有线电视网络Problem给定一张n个点m条边的无向图,求最少去掉多少个点,可以使图不连通。如果不管去掉多少个点,都无法使原图不连通,则直接返回n。Solution最小割模型的通用分析方式:通过原图构造一个流网络......
  • Codeforces Round 930 (Div. 1) C dij 建图
    离较好的方法差一点。考虑到了可以按照枚举属性并按照当前属性从小到大排序,这样可以从一个点到大另一个点。设当前在排序序列中点为\(i\)当\(i\)走向\(k,i>=k\)需要支付\(c_k\)的代价。而\(i\)到\(k,i<k\)则需\(k-i+c_k\)的代价。则对于不同的\(i\)由于代价没有连续性,当时想......