Atcoder E - Connecting Cities 线段树

Solution

求最小生成树,考虑使用 p r i m prim prim算法。
首先定义已在生成树中的点集为 A A A,不在的为 B B B
线段树维护 5 5 5个量: A A A连到 B B B的最小边权, A 、 B A、B AB a i + D i 、 a i − D i a_i+Di、a_i-Di ai+DiaiDi的最小值。每次相当于从 B B B中删去一个点,并加入 A A A

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=200010;
const LL inf=(1LL<<60);
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n;LL d,a[Maxn];
struct Node{LL v;int x;Node(LL _v=0,int _x=0){v=_v;x=_x;}};
bool operator<(Node a,Node b){return a.v<b.v;}
struct Seg{int l,r,lc,rc,pos;Node p[5];}tr[Maxn<<1];
int tot;
void up(int x)
{
	int lc=tr[x].lc,rc=tr[x].rc;
	for(int i=0;i<5;i++)
	if(tr[lc].p[i]<tr[rc].p[i])
	{
		tr[x].p[i]=tr[lc].p[i];
		if(i==4)tr[x].pos=tr[lc].pos;
	}
	else
	{
		tr[x].p[i]=tr[rc].p[i];
		if(i==4)tr[x].pos=tr[rc].pos;
	}
	if(tr[lc].p[2].v!=inf&&tr[rc].p[1].v!=inf)
	{
		LL t=tr[lc].p[2].v+tr[rc].p[1].v;
		if(t<tr[x].p[4].v)tr[x].p[4]=Node(t,tr[lc].p[2].x),tr[x].pos=tr[rc].p[1].x;
	}
	if(tr[lc].p[0].v!=inf&&tr[rc].p[3].v!=inf)
	{
		LL t=tr[lc].p[0].v+tr[rc].p[3].v;
		if(t<tr[x].p[4].v)tr[x].p[4]=Node(t,tr[rc].p[3].x),tr[x].pos=tr[lc].p[0].x;
	}
}
void build(int l,int r)
{
	int x=++tot;
	tr[x].l=l;tr[x].r=r;
	for(int i=0;i<5;i++)tr[x].p[i]=Node(inf,0);
	if(l==r)
	{
		if(l!=1)
		{
			tr[x].p[0]=Node(a[l]-(LL)l*d,l);
			tr[x].p[1]=Node(a[l]+(LL)l*d,l);
			tr[x].p[2]=tr[x].p[3]=tr[x].p[4]=Node(inf,0);
		}
		else
		{
			tr[x].p[0]=tr[x].p[1]=tr[x].p[4]=Node(inf,0);
			tr[x].p[2]=Node(a[l]-(LL)l*d,l);
			tr[x].p[3]=Node(a[l]+(LL)l*d,l);
		}		
		return;
	}
	int mid=l+r>>1;
	tr[x].lc=tot+1,build(l,mid);
	tr[x].rc=tot+1,build(mid+1,r);
	up(x);
}
void modify(int x,int p)
{
	for(int i=0;i<5;i++)tr[x].p[i]=Node(inf,0);
	if(tr[x].l==tr[x].r)
	{
		int l=tr[x].l;
		tr[x].p[0]=tr[x].p[1]=tr[x].p[4]=Node(inf,0);
		tr[x].p[2]=Node(a[l]-(LL)l*d,l);
		tr[x].p[3]=Node(a[l]+(LL)l*d,l);
		return;
	}
	int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
	if(p<=mid)modify(lc,p);
	else modify(rc,p);
	up(x);
}
int main()
{
	n=read(),d=read();
	for(int i=1;i<=n;i++)a[i]=read();
	build(1,n);
	int m=n-1;LL ans=0;
	while(m--)ans+=tr[1].p[4].v,modify(1,tr[1].pos);
	printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是代码形式的电话线路图状态: ``` @startuml title Telephone State Diagram [*] --> Idle : Initial State Idle --> Dialing : Off Hook Event Dialing --> Connecting : Valid Number Event Dialing --> Disconnected : Invalid/Wrong Number Event Connecting --> TimeOut : Timeout Event Connecting --> Connected : Called Phone Answers Event Ringing --> Connected : Called Phone Answers Event Connected --> Idle : On Hook Event Connected --> Busy Tone : Line Busy Event Connected --> TimeOut : Timeout Event Connected --> Disconnected : Timeout Event Connected --> Ringing : Play Message Event @enduml ``` 解释一下: - 初始状态为空闲状态(`[*] --> Idle : Initial State`)。 - 当电话机摘机时,电话状态从空闲状态转入拨号状态(`Idle --> Dialing : Off Hook Event`)。 - 当拨号有效号码时,电话状态从拨号状态转入连接状态(`Dialing --> Connecting : Valid Number Event`)。 - 当拨号号码无效或错误时,电话状态从拨号状态转入未连接状态(`Dialing --> Disconnected : Invalid/Wrong Number Event`)。 - 当连接超时时,电话连接状态从连接状态转入超时状态(`Connecting --> TimeOut : Timeout Event`)。 - 当被拨打的电话接听时,电话连接状态从连接状态或响铃状态转入已连接状态(`Connecting --> Connected : Called Phone Answers Event` 或 `Ringing --> Connected : Called Phone Answers Event`)。 - 当已连接状态的电话机挂机时,电话状态从已连接状态转入空闲状态(`Connected --> Idle : On Hook Event`)。 - 当已连接状态的电话线路忙碌时,电话状态从已连接状态转入忙音状态(`Connected --> Busy Tone : Line Busy Event`)。 - 当已连接状态的电话连接超时时,电话状态从已连接状态转入未连接状态(`Connected --> TimeOut : Timeout Event`)。 - 当已连接状态的电话播放信息时,电话状态从已连接状态转入响铃状态(`Connected --> Ringing : Play Message Event`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值