1657: [Usaco2006 Mar]Mooo 奶牛的歌声 (悬线法 或 线段树 )

1657: [Usaco2006 Mar]Mooo 奶牛的歌声

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 746  Solved: 526
[Submit][Status][Discuss]

Description

Farmer John's N (1 <= N <= 50,000) cows are standing in a very straight row and mooing. Each cow has a unique height h in the range 1..2,000,000,000 nanometers (FJ really is a stickler for precision). Each cow moos at some volume v in the range 1..10,000. This "moo" travels across the row of cows in both directions (except for the end cows, obviously). Curiously, it is heard only by the closest cow in each direction whose height is strictly larger than that of the mooing cow (so each moo will be heard by 0, 1 or 2 other cows, depending on not whether or taller cows exist to the mooing cow's right or left). The total moo volume heard by given cow is the sum of all the moo volumes v for all cows whose mooing reaches the cow. Since some (presumably taller) cows might be subjected to a very large moo volume, FJ wants to buy earmuffs for the cow whose hearing is most threatened. Please compute the loudest moo volume heard by any cow.

Farmer John的N(1<=N<=50,000)头奶牛整齐地站成一列“嚎叫”。每头奶牛有一个确定的高度h(1<=h<=2000000000),叫的音量为v (1<=v<=10000)。每头奶牛的叫声向两端传播,但在每个方向都只会被身高严格大于它的最近的一头奶牛听到,所以每个叫声都只会 被0,1,2头奶牛听到(这取决于它的两边有没有比它高的奶牛)。 一头奶牛听到的总音量为它听到的所有音量之和。自从一些奶牛遭受巨大的音量之后,Farmer John打算买一个耳罩给被残害得最厉 害的奶牛,请你帮他计算最大的总音量。

Input

* Line 1: A single integer, N.

* Lines 2..N+1: Line i+1 contains two space-separated integers, h and v, for the cow standing at location i.

    第1行:一个正整数N.

    第2到N+1行:每行包括2个用空格隔开的整数,分别代表站在队伍中第i个位置的奶牛的身高以及她唱歌时的音量.

Output

* Line 1: The loudest moo volume heard by any single cow.


    队伍中的奶牛所能听到的最高的总音量.

Sample Input

3
4 2
3 5
6 10

INPUT DETAILS:

Three cows: the first one has height 4 and moos with volume 2, etc.

Sample Output

7

HINT

     队伍中的第3头奶牛可以听到第1头和第2头奶牛的歌声,于是她能听到的总音量为2+5=7.虽然她唱歌时的音量为10,但并没有奶牛可以听见她的歌声.

Source

Silver


做这道题快做哭了。。。。。。

本来想想个别出心裁的方法,就写了排序后用线段树去搞,结果一直在wa,对拍也拍不出错,然后弃疗,想别的方法,用悬线法O(n)解决,AC了,这时数据也要来了,发现......md如果只有一个元素我没有判断导致线段树会查询到它本身,加了判断AC了,感动到哭。。。。。


悬线法代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<climits>
#include<string>
#define N 50005
using namespace std;
int l[N],r[N],h[N];
int n,c[N],ans,v[N];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		{
			scanf("%d%d",&h[i],&v[i]);
			l[i]=r[i]=i;
		}
	for(int i=1;i<=n;i++)
		while(l[i]-1&&h[l[i]-1]<h[i])l[i]=l[l[i]-1];
	for(int i=n;i;i--)
		while(r[i]+1<=n&&h[r[i]+1]<h[i])r[i]=r[r[i]+1];
	for(int i=1;i<=n;i++)
		{
			if(l[i]-1)c[l[i]-1]+=v[i];
			if(r[i]+1<=n)c[r[i]+1]+=v[i];
		}for(int i=1;i<=n;i++)ans=max(ans,c[i]);
	printf("%d\n",ans);
}


线段树+排序:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<climits>
#include<string>
#define N 50010
#define M 400020
using namespace std;
typedef long long ll;
ll n;
ll h[N],v[N];
struct edge{ll l,r,mx;}e[M];
void build(ll u,ll l,ll r)
{
	e[u].l=l,e[u].r=r,e[u].mx=0;
	if(l==r)return;ll mid=(l+r)>>1;
	build(u<<1,l,mid);build(u<<1|1,mid+1,r);
}
void pushup(ll u){e[u].mx=max(e[u<<1].mx,e[u<<1|1].mx);}
void add(ll u,ll x,ll val)
{
	ll l=e[u].l,r=e[u].r,mid=(l+r)>>1;
	if(l==r){e[u].mx=val;return;}
	if(x<=mid)add(u<<1,x,val);
	else add(u<<1|1,x,val);
	pushup(u);
}
ll t;
void query(ll u,ll x,ll y,ll hx)
{
	ll l=e[u].l,r=e[u].r,mid=(l+r)>>1;
	if(l==r){if(e[u].mx>hx)t=l;return;}
	if(y<=mid)
		{
			if(e[u<<1].mx>hx)query(u<<1,x,y,hx);
			else t=-1;
		}
	else if(x>mid)
		{
			if(e[u<<1|1].mx>hx)query(u<<1|1,x,y,hx);
			else t=-1;
		}
	else
		{
			if(e[u<<1|1].mx>hx)query(u<<1|1,x,y,hx);
			else if(e[u<<1].mx>hx)query(u<<1,x,y,hx);
			else t=-1;
		}
}
void query1(ll u,ll x,ll y,ll hx)
{
	ll l=e[u].l,r=e[u].r,mid=(l+r)>>1;
	if(l==r){if(e[u].mx>hx)t=l;return;}
	if(y<=mid)
		{
			if(e[u<<1].mx>hx)query1(u<<1,x,y,hx);
			else t=-1;
		}
	else if(x>mid)
		{
			if(e[u<<1|1].mx>hx)query1(u<<1|1,x,y,hx);
			else t=-1;
		}
	else
		{
			if(e[u<<1].mx>hx)query1(u<<1,x,y,hx);
			else if(e[u<<1|1].mx>hx)query1(u<<1|1,x,y,hx);
			else t=-1;
		}
}
ll ans[N],ret;
int main()
{
//	freopen("bzoj1657.in","r",stdin);
//	freopen("bzoj1657.out","w",stdout);
	scanf("%lld",&n);build(1,1,n);
	for(ll i=1;i<=n;i++)
		{
			scanf("%lld%lld",&h[i],&v[i]);
			query(1,1,i-1,h[i]);add(1,i,h[i]);
			if(t!=-1)ans[t]+=v[i];
		}build(1,1,n);
	for(ll i=n;i;i--)
		{
			query1(1,i+1,n,h[i]);
			add(1,i,h[i]);
			if(t!=-1)ans[t]+=v[i];
		}
	for(ll i=1;i<=n;i++){ret=max(ret,ans[i]);}
	printf("%lld\n",ret);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值