Codeforces Good Bye 2017: F. New Year and Rainbow Roads(模拟)

time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Roy and Biv have a set of n points on the infinite number line.

Each point has one of 3 colors: red, green, or blue.

Roy and Biv would like to connect all the points with some edges. Edges can be drawn between any of the two of the given points. The cost of an edge is equal to the distance between the two points it connects.

They want to do this in such a way that they will both see that all the points are connected (either directly or indirectly).

However, there is a catch: Roy cannot see the color red and Biv cannot see the color blue.

Therefore, they have to choose the edges in such a way that if all the red points are removed, the remaining blue and green points are connected (and similarly, if all the blue points are removed, the remaining red and green points are connected).

Help them compute the minimum cost way to choose edges to satisfy the above constraints.

Input

The first line will contain an integer n (1 ≤ n ≤ 300 000), the number of points.

The next n lines will contain two tokens pi and ci (pi is an integer, 1 ≤ pi ≤ 109ci is a uppercase English letter 'R', 'G' or 'B'), denoting the position of the i-th point and the color of the i-th point. 'R' means red, 'G' denotes green, and 'B' means blue. The positions will be in strictly increasing order.

Output

Print a single integer, the minimum cost way to solve the problem.

Examples
input
4
1 G
5 R
10 B
15 G
output
23
input
4
1 G
2 R
3 B
10 G
output
12

发现错误没时间改了,就差几秒钟交不上去了。。

题意:一条横轴上有n个点,每个点都有一个颜色(RGB三种颜色中的一种),你可以将任意两点连接起来,代价为两点之间的距离,问如何以最小的代价满足:①删除所有红点(R)后剩下的点全部连通;②删除所有蓝色(B)点后剩下的点全部连通


思路:

首先很显然将一个红点和一个蓝点连起来没有意义

对于没有绿点的情况:将所有红点用一条直线连起来,将所有蓝点用一条直线连起来就ok

对于有绿点的情况,对于相邻的两个绿点有且只有两种连法:

(△是绿点)

两种取最优的,然后最两边的绿点外的所有红点蓝点全部连一条线到最近的绿点即可


#include<stdio.h>
#include<algorithm>
using namespace std;
#define LL long long
typedef struct
{
	int x;
	int tp;
}Point;
Point s[300005];
int Min[4], Max[4];
LL a1[300005];
int main(void)
{
	LL ans;
	char ch;
	int i, n, bet, last1, last2, cnt;
	scanf("%d", &n);
	for(i=1;i<=3;i++)
		Min[i] = 1e9+1, Max[i] = 0;
	for(i=1;i<=n;i++)
	{
		scanf("%d %c", &s[i].x, &ch);
		if(ch=='R')  s[i].tp = 1, Max[1] = max(s[i].x, Max[1]), Min[1] = min(s[i].x, Min[1]);
		if(ch=='G')  s[i].tp = 3, Max[3] = max(s[i].x, Max[3]), Min[3] = min(s[i].x, Min[3]);
		if(ch=='B')  s[i].tp = 2, Max[2] = max(s[i].x, Max[2]), Min[2] = min(s[i].x, Min[2]);
	}
	if(Max[3]==0)
	{
		ans = 0;
		if(Max[1])
			ans += Max[1]-Min[1];
		if(Max[2])
			ans += Max[2]-Min[2];
		printf("%lld\n", ans);
	}
	else
	{
		ans = Max[3]-Min[3];
		if(Max[1])
		{
			cnt = bet = 0, last1 = last2 = -1;
			for(i=1;i<=n;i++)
			{
				if(s[i].tp==3)
				{
					if(last2!=-1)
					{
						ans += s[i].x-s[last2].x;
						bet = max(bet, s[i].x-s[last2].x);
					}
					if(last1!=-1)
					{
						if(bet)
							a1[++cnt] = s[i].x-s[last1].x-bet;
						ans -= bet;
					}
					last1 = last2 = i;
					bet = 0;
				}
				else if(s[i].tp==1)
				{
					if(last2!=-1)
					{
						ans += s[i].x-s[last2].x;
						bet = max(bet, s[i].x-s[last2].x);
					}
					last2 = i;
				}
			}
		}
		if(Max[3])
		{
			cnt = bet = 0, last1 = last2 = -1;
			for(i=1;i<=n;i++)
			{
				if(s[i].tp==3)
				{
					if(last2!=-1)
					{
						ans += s[i].x-s[last2].x;
						bet = max(bet, s[i].x-s[last2].x);
					}
					if(last1!=-1)
					{
						if(bet)
							a1[++cnt] += s[i].x-s[last1].x-bet;
						if(a1[cnt]>s[i].x-s[last1].x)
							ans -= a1[cnt]-s[i].x+s[last1].x;
						ans -= bet;
					}
					last1 = last2 = i;
					bet = 0;
				}
				else if(s[i].tp==2)
				{
					if(last2!=-1)
					{
						ans += s[i].x-s[last2].x;
						bet = max(bet, s[i].x-s[last2].x);
					}
					last2 = i;
				}
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值