CF786B Legacy

CF786B Legacy

Legacy

题面翻译

Rick 和他的同事们做出了一种新的带放射性的婴儿食品(???根据图片和原文的确如此...),与此同时很多坏人正追赶着他们。因此 Rick 想在坏人们捉到他之前把他的遗产留给 Morty。

在宇宙中一共有 n 个星球标号为 1n。Rick 现在身处于标号为 s 的星球(地球)但是他不知道 Morty 在哪里。

众所周知,Rick 有一个传送枪,他用这把枪可以制造出一个从他所在的星球通往其他星球(也包括自己所在的星球)的单行道路。但是由于他还在用免费版,因此这把枪的使用是有限制的。

默认情况下他不能用这把枪开启任何传送门。在网络上有 q 个售卖这些传送枪的使用方案。每一次你想要实施这个方案时你都可以购买它,但是每次购买后只能使用一次。每个方案的购买次数都是无限的。

网络上一共有三种方案可供购买:

  • 开启一扇从星球 v 到星球 u 的传送门;
  • 开启一扇从星球 v 到标号在 [l,r] 区间范围内任何一个星球的传送门。(即这扇传送门可以从一个星球出发通往多个星球)
  • 开启一扇从标号在 [l,r] 区间范围内任何一个星球到星球 v 的传送门。(即这扇传送门可以从多个星球出发到达同一个星球)

Rick 并不知道 Morty 在哪儿,但是 Unity 将要通知他 Morty 的具体位置,并且他想要赶快找到通往所有星球的道路各一条并立刻出发。因此对于每一个星球(包括地球本身)他想要知道从地球到那个星球所需的最小钱数。

输入数据:

输入数据的第一行包括三个整数 nqs 分别表示星球的数目,可供购买的方案数目以及地球的标号。

接下来的 q 行表示 q 种方案。

  • 输入 1 v u w 表示第一种方案,其中 v,u 意思同上,w 表示此方案价格。
  • 输入 2 v l r w 表示第二种方案,其中 v,l,r 意思同上,w 表示此方案价格。
  • 输入 3 v l r w 表示第三种方案,其中 v,l,r 意思同上,w 表示此方案价格。

输出格式:

输出一行用空格隔开的 n 个整数分别表示从地球到第 i 个星球所需的最小钱数。如果不能到达那个星球,输出-1。

说明:
在第一组测试样例里,Rick 可以先购买第 4 个方案再购买第 2 个方案从而到达标号为 2 的星球.

【数据范围】
对于 100% 的数据,1n,q1051w109

-----------------------------------------------------------------------------------

观察题目我们发现一种特殊的连边:

开启一扇从标号在 [l,r] 区间范围内任何一个星球到星球 v 的传送门

这让我们很难不想到线段树!

之后我就不会了捏
开始翻题解了捏

看完题解之后我满血复活:这就是板子!
我们数据结构选手看什么都像板子捏

我们考虑把所有点拆成入点和出点
(怎么那么像二分图啊喂)

建立两颗线段树,一颗树的叶子节点对应入点,一颗对应出点。
画图的话可以参考大佬的题解:

然后对于每个非叶子节点:

向左右儿子各连一条费用为0的边

对于每个连接 x->[l,r],在线段树上对每个满足:
l<=t[rt].l&&t[rt].r<=r 的节点 rt ,连一条 x->rt 的边
容易证明这样等价于x向[l,r]区间内每个点连边

建完边之后直接跑最短路就行了

然后我们来扣一些细节:
水一些时间

首先,本题n=1e5,那么线段树最多有4e5的节点。;
对于两颗线段树,就有8e5将近1e6个节点,所以数组要开够

还有就是Edge:8e5个树上节点每个点两条边,再加上询问中至多1e5*logn条边!
(差点因为这个被卡)

现在是代码时间:

#include<bits/stdc++.h>
#define int long long
#define d lld
#define ls (x<<1)
#define rs (x<<1|1)
const int N=5e5;
const int NN=1e6+5;
const int inf=1e17+5;
using namespace std;
int head[NN],vis[NN],dis[NN],a[NN];
int n,m,e_cnt,s;
void init(){for(int i=0;i<NN;i++)dis[i]=inf;}
struct Tree{
int l,r;
}t[NN<<1];
struct Edge{
int to,nxt,w;
}e[NN<<1];
void add(int x,int y,int w)
{
//cout<<"add:"<<x<<" "<<y<<" "<<w<<"\n";
e[++e_cnt]={y,head[x],w};
head[x]=e_cnt;
}
void build(int x,int l,int r)
{
t[x].l=l,t[x].r=r;
if(l==r)
{
a[l]=x;
return ;
}
add(x,ls,0);add(x,rs,0);//in_Tree
add(ls+N,x+N,0);add(rs+N,x+N,0);//out_Tree
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
}
void connect(int x,int u,int ll,int rr,int w,int opt)
{
if(ll<=t[x].l&&t[x].r<=rr)
{
switch(opt)
{
case 0:
add(u+N,x,w);
break;
case 1:
add(x+N,u,w);
break;
}
return ;
}
int mid=t[x].l+t[x].r>>1;
if(ll<=mid)connect(ls,u,ll,rr,w,opt);
if(rr>mid)connect(rs,u,ll,rr,w,opt);
}
struct Node{
int id,val;
bool operator <(const Node &nn)const{
return nn.val<val;
}
};
priority_queue<Node> Q;
void dijkstra(int s)
{
dis[s]=0;Q.push({s,0});
while(!Q.empty())
{
int u=Q.top().id;Q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to,w=e[i].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
Q.push({v,dis[v]});
}
}
}
}
void work()
{
init();
cin>>n>>m>>s;
build(1,1,n);
for(int i=1;i<=n;i++)
{
add(a[i],a[i]+N,0);add(a[i]+N,a[i],0);
}
for(int i=1,x,y[2],w,opt;i<=m;i++)
{
scanf("%lld%lld%lld",&opt,&x,&y[0]);
if(opt==1)
{
scanf("%lld",&w);
add(a[x]+N,a[y[0]],w);
continue;
}
opt-=2;
scanf("%lld%lld",&y[1],&w);
connect(1,a[x],y[0],y[1],w,opt);
}
dijkstra(a[s]+N);
for(int i=1;i<=n;i++)
{
printf("%lld ",dis[a[i]]!=inf? dis[a[i]] : -1);
}
return ;
}
#undef int
int main()
{
freopen("CF786B.in","r",stdin);//freopen("CF786B.out","w",stdout);
work();
}
posted @   liuboom  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示