首页 > 其他分享 >P10538 [APIO2024] 星际列车 题解

P10538 [APIO2024] 星际列车 题解

时间:2024-06-22 20:10:02浏览次数:8  
标签:列车 le 10 int 题解 APIO2024 maxn vi P10538

题意:

有 \(n\) 个行星,编号为 \(0\sim n-1\) 。

有 \(m\) 辆星际列车,第 \(i\) 辆列车在时刻 \(a_i\) 从行星 \(x_i\) 出发,在时刻 \(b_i\) 到达行星 \(y_i\) ,代价为 \(c_i\) 。换乘条件为上一辆车的终点和下一辆车的起点相同,且上一辆车到达时刻 \(\le\) 下一辆车出发时刻。

你需要吃 \(w\) 顿饭,第 \(i\) 顿饭必须在 \([l_i,r_i]\) 时刻吃。如果在列车上吃则免费,如果在 \(i\) 号行星吃则代价为 \(t_i\)。

时刻 \(0\) 时你在 \(0\) 号行星上,求到达 \(n-1\) 号行星的最小代价,如果无法到达输出 \(-1\) 。

\(2\le n\le 10^5,0\le m,w\le 10^5,0\le x_i\neq y_i\lt n,1\le a_i\lt b_i\le 10^9,1\le t_i,c_i\le 10^9,1\le l_i\le r_i\le 10^9\)。

时间限制 \(\texttt{1s}\) ,空间限制 \(\texttt{1000MB}\) 。

分析:

如果把行星、时刻二元组看成一个状态,容易发现状态很多,但是只有某辆列车的起始、终止状态是有用的。

令 \(f_i\) 为搭乘完第 \(i\) 辆列车的最小代价,容易写出转移方程:

\[f_i=\min\limits_{b_j\le a_i,y_j=x_i}f_j+g(b_j,a_i)\cdot t_{x_i}+c_i \]

其中 \(g(x,y)\) 表示完全包含于区间 \((x,y)\) 的区间 \([l_i,r_i]\) 个数。

对起始、终止状态建立虚点,暴力跑上述转移,时间复杂度 \(\mathcal O(n^2)\)。

将所有列车按照 \(y_j\) 分类,每一类中按 \(b_j\) 升序排序,那么可以转移到 \(f_i\) 的是第 \(x_i\) 类中的一段前缀。

注意到转移代价 \(w(j,i)=g(b_j,a_i)\cdot t_i +c_i\) 满足四边形不等式(根据 \(g\) 的定义,交叉优于包含),因此 \(f\) 满足决策单调性

使用二分队列优化,指针扫描加入所有 \(b_j\le a_i\) 的决策点,转移过程可以看我的笔记

至于 \(g\) 的求法,只是一个简单的动态二维数点问题,用可持久化线段树维护。

时间复杂度\(\mathcal O(n\log^2n)\)。

#include<bits/stdc++.h>
#define ll long long
#define vi vector<int>
#define lsh(x) (int)(lower_bound(e+1,e+k+1,x)-e)
using namespace std;
const int maxn=4e5+5;
const ll inf=1e18;
int k,tot;
int e[maxn],rt[maxn];
int hd[maxn],tl[maxn],px[maxn],py[maxn];
ll dp[maxn];
vi vec[maxn],vx[maxn],vy[maxn];
struct train
{
    int a,b,c,x,y;
}d[maxn];
struct node
{
    int ls,rs,sum;
}f[20*maxn];
struct oper
{
    int x,l,r;
};
vector<oper> q[maxn];
void insert(int &p,int l,int r,int x)
{
    f[++tot]=f[p],p=tot;
    if(l==r) return f[p].sum++,void();
    int mid=(l+r)>>1;
    x<=mid?insert(f[p].ls,l,mid,x):insert(f[p].rs,mid+1,r,x);
    f[p].sum=f[f[p].ls].sum+f[f[p].rs].sum;
}
int query(int p,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return f[p].sum;
    if(!p||l>R||r<L) return 0;
    int mid=(l+r)>>1;
    return query(f[p].ls,l,mid,L,R)+query(f[p].rs,mid+1,r,L,R);
}
ll solve(int n,int m,int w,vi t,vi x,vi y,vi a,vi b,vi c,vi l,vi r)
{
    for(int i=0;i<m;i++) e[++k]=a[i],e[++k]=b[i];
    for(int i=0;i<w;i++) e[++k]=l[i],e[++k]=r[i];
    sort(e+1,e+k+1);
    k=unique(e+1,e+k+1)-e-1;
    for(int i=0;i<m;i++) d[i+1]={lsh(a[i]),lsh(b[i]),c[i],x[i],y[i]};
    for(int i=0;i<w;i++) vec[lsh(l[i])].push_back(lsh(r[i]));
    for(int i=k;i>=1;i--)
    {
        rt[i]=rt[i+1];
        for(auto p:vec[i]) insert(rt[i],1,k,p);
    }
    sort(d+1,d+m+1,[&](train u,train v){return u.a<v.a;});
    d[++m]={k+1,k+2,0,n-1,n-1};
    for(int i=0;i<=m;i++) vx[d[i].x].push_back(i),vy[d[i].y].push_back(i);
    for(int i=0;i<n;i++)
    {
        hd[i]=1,tl[i]=0,q[i].push_back({0,0,0});
        sort(vy[i].begin(),vy[i].end(),[&](int u,int v){return d[u].b<d[v].b;});
    }
    auto calc=[&](int j,int i)
    {
        return min(dp[j]+1ll*query(rt[d[j].b+1],1,k,1,d[i].a-1)*t[d[i].x]+d[i].c,inf);
    };
    for(int i=1;i<=m;i++)
    {
        int u=d[i].x,&h=hd[u],&t=tl[u],&j=py[u],k=px[u]++;
        while(j<vy[u].size()&&d[vy[u][j]].b<=d[i].a)
        {
            while(h<=t&&calc(vy[u][j],vx[u][q[u][t].l])<=calc(q[u][t].x,vx[u][q[u][t].l])) t--;
            if(t==q[u].size()-1) q[u].push_back({0,0,0});
            if(h>t) q[u][++t]={vy[u][j],k,(int)vx[u].size()-1};
            else
            {
                int l=max(k-1,q[u][t].l-1),r=q[u][t].r+1;
                while(r-l>1)
                {
                    int mid=(l+r)>>1;
                    calc(vy[u][j],vx[u][mid])<=calc(q[u][t].x,vx[u][mid])?r=mid:l=mid;
                }
                if(r<=vx[u].size()-1) q[u][t].r=r-1,q[u][++t]={vy[u][j],r,(int)vx[u].size()-1};
            }
            j++;
        }
        while(h<=t&&q[u][h].r<k) h++;
        dp[i]=h<=t?calc(q[u][h].x,i):inf;
    }
    return dp[m]!=inf?dp[m]:-1;
}

标签:列车,le,10,int,题解,APIO2024,maxn,vi,P10538
From: https://www.cnblogs.com/peiwenjun/p/18262677

相关文章

  • qoj8542 Add One 2 题解
    题目链接点击打开链接题目解法我们先考虑什么样的序列\(x_1,...,x_n\)是可以被得到的对于\(x_i>x_{i+1}\)的位置,我们需要至少对前缀\([1,i]\)做\(x_i-x_{i+1}\)次操作;对于\(x_{i-1}<x_{i}\)的位置,我们需要至少对后缀\([i,n]\)做\(x_i-x_{i-1}\)次操作我们需要......
  • [集训队互测 2023] 树哈希 题解报告
    [集训队互测2023]树哈希题解报告/bx/bx/bxzky!!!题意给定常数\(q\),定义一棵以\(1\)为根的有根树\(T\)的\(s(T)\)为\(T\)中本质不同的子树数量,定义其权值为\(q^{s(T)}\)。给定\(n\),对于\(i=1,\dots,n\)求所有大小为\(i\)的有标号有根树的权值之和对\(P\)......
  • CF1978E Computing Machine 题解
    好写程度:\(E>D>C\)。好想程度:\(C>D=E\)。总结:C是全场最难。我们考虑把两个操作对全体的\(a_i,b_i\)都做一遍,会发现我们只会做这两遍,不会再有嵌套的了,因为都做过一遍后\(\{a\}\)中0的数量只会减少,而且即使再做一遍也无法给\(\{b\}\)改成不一样的了,比较显然。下文中令......
  • [题解]AT_abc267_f [ABC267F] Exactly K Steps
    大家好,我是毒瘤,喜欢用玄学算法过题。发现题解区没有这个做法,于是来发一篇。思路不难发现如果一个点对\((u,v)\)的距离为\(d\),那么在这棵树以\(u\)为根时,\(v\)的深度为\(d\)。于是考虑换根DP。首先思考如何计算答案。显然我们可以将查询离线下来,然后当换根到以\(u\)......
  • BD202301·公园题解
    BD202301·公园题解考虑将整个移动过程分为两个部分:小度和度度熊汇合之前小度和度度熊汇合之后第一部分可以直接用Dijkstra算法直接搞定,第二部分可以考虑反向思考,从N点出发做一次Dijkstra,最后枚举每个汇合点即可得到答案。时间复杂度\(\Theta(nlogn)\)代码如下:#include......
  • [题解]AT_abc264_e [ABC264E] Blackout 2
    思路一道很经典的题,运用了一种叫「时光倒流」的技巧。「时光倒流」本质上就是将所有删边(或删点)的操作,通过倒序循环求值的方式转化为加边(或加点)。「时光倒流」具体实现通常伴随着并查集出现,维护一个连通块的某种性质。首先,我们需要将所有从始至终没有删过的边加入并查集。在这......
  • [题解]AT_abc263_d [ABC263D] Left Right Operation
    思路首先,不难发现最终的序列一定是形如下面的序列:\[l,\dots,l,a_i,a_{i+1},\dots,a_{i+j},r,\dotsr\]那么,我们就可以将其分为三段,每段都单独维护。首先,对于第一段,我们可以枚举出最后一个\(l\)的位置\(x\),那么和为\(x\timesl\)。对于第二段显然可以用前......
  • [题解]AT_abc256_h [ABC256Ex] I like Query Problem
    思路首先可以看一下P4145,在P4145中使用了一种叫势能线段树的Trick。对于势能线段树,我个人的理解是,对于一段区间(或一个点)直接暴力维护,在经过很少的次数后操作将没有意义的题就可以使用势能线段树。在本题中,如果没有推平操作,显然我们可以直接使用势能线段树,时间复杂度可以轻......
  • [题解]AT_abc263_f [ABC263F] Tournament
    先为大家毙掉一个错解思路首先不难发现,如果将整棵比赛的对战图画出来,一定是一个满二叉树。不妨将令一个节点\(u\)的左右儿子编号分别为\(2u\)和\(2u+1\)。然后定义\(dp_{u,d}\)表示将\(u\)为根的子树内的选手全部比赛完,并且\(u\)已经赢了\(d\)场的最大结果。发......
  • [题解]AT_abc237_g [ABC237G] Range Sort Query
    思路将小于等于\(x\)的元素赋为\(1\),其余的赋为\(0\)。那么一个区间内小于等于\(x\)的数量就是区间中\(1\)的数量。那么,将区间升序排列就是将\(1\)先堆在前面,将\(0\)堆到后面;降序排列同理。考虑动态维护\(x\)的位置,记其位置为\(t\)。如果\(l\leqt\leqr\),则......