zoj 3724 线段树

比赛的时候感觉这道题可以写,在那里分析了很久,就对于u<v的时候想出来怎么写了,对于v<u的情况想不出来该怎么处理和转化,然后看了别人的题解,昨天写出了代码,结果wa到今天下午,一直想不通为什么,然后不断的改正发现了两处错误,第一:就是sort写的有问题,当u和v都相等的时候应该在根据是边和问题再排一次序,还有就是对于问u和v相等的时候没有处理,导致结果不对,将这两个一改就ac了,交了无数次啊!比赛要是写的话那么紧张更找不到错了!

题目意思很容易懂,这里就不啰嗦了。

解题思路:刚一看感觉是最短路的题,应该是图,但是再一想,有n-1条有向边你可以随意用但是那些小道只可以用一次,所以就是对于特定的问题,根据那些小道对于每个点的距离进行更新。

对于问题进行离散处理,和边放在一块进行sort。对于u>v和u<v进行分开处理。

1、对于u<v,那么首先可以得到的一个解就是sum[v]-sum[u],要求最小的解,那么就是一些小道可以减小的,因为那些小道只可以用一次,所以对这个结果产生影响的只有u‘和v’,其中v'>v && u'<u,所以对u和v进行u降序v升序排列(要注意当u和v相同的时候小道应该放在询问问题的前面),然后对于一个小道边,则对u'到n进行更新,更新的值为sum[u']-sum[v']-w,代表这条边对于这个区间内可以减去的最大的值,对于问题,则直接在线段树中查找在u的位置的最大值,结果为sum[u]-sum[v]-que();

2、对于u>v,首先进行和上面的一样的sort,类似于上面的分析,对于问题点u到点v,因为只有一个小道可以选择,那么对其产生影响的边只有u'和v‘,其中u’<u && v>v',     

记在这些点中,这些标记点所在的位置为1,  v',   v,   u,    u',   n

所以边v'到u‘对v到u的边长为sum[u']-sum[u]+sum[v]-sum[v']+w',而我们的线段树每次都是更新找最大值,所以就可以转换为

sum[n]-sum[u]+sum[v]-(sum[n]-sum[u']+sum[v']+w'),前半部分固定,所以就应该使得后面减去的部分尽可能大

所以当遇到小道时,就对于v'到n进行sum[n]-sum[u']+sum[v']+w')的最大值更新。

对遇到询问时,则结果为sum[n]-sum[u]+sum[v]-query(u);

表达能力不强,望见谅啊!

/
// File Name: 333.cpp
// Author: wang
// mail: 
// Created Time: 2013/9/19 17:22:21
/
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <cstring>
#include <cmath>

#include <algorithm>
#include<iostream>
#include<queue>
#include <map>
using namespace std;
typedef long long ll;
#define INF (INT_MAX/10)
#define SQR(x) ((x)*(x))
#define rep(i, n) for (int i=0; i<(n); ++i)
#define repf(i, a, b) for (int i=(a); i<=(b); ++i)
#define repd(i, a, b) for (int i=(a); i>=(b); --i)
#define clr(ar,val) memset(ar, val, sizeof(ar))
#define inf 1<<30 
#define N 100005
#define M 200005
ll sum[N];
struct no{
	int u,v,i,sign;
	ll w;
	void set(int _u,int _v,ll _w,int _i,int _s)
	{
		u=_u; v=_v; w=_w; i=_i; sign=_s;
	}
};
no add[2*M],del[2*M];
ll ans[M];
int la,lb,n,m,t;
struct node
{
	int l,r;
	ll Max;
};
node a[N*6];
void bulidtree(int s,int l,int r,ll pp)
{
	a[s].l=l; a[s].r=r; a[s].Max=pp;
	if(l==r) return;
	int mid=(l+r)/2;
	bulidtree(2*s,l,mid,pp);
	bulidtree(2*s+1,mid+1,r,pp);
}
bool cmp(no a,no b)
{
	if(a.u==b.u) return a.sign<b.sign;
	else return a.u>b.u;	
}
void pushdown(int s)
{
	a[2*s].Max=max(a[2*s].Max,a[s].Max);
	a[2*s+1].Max=max(a[2*s+1].Max,a[s].Max);
}
void update(int s,int l,int r,ll x)
{
	if(a[s].l>=l && a[s].r<=r)
	{
		a[s].Max=max(x,a[s].Max);
		return ;
	}
	pushdown(s);
	int mid=(a[s].l+a[s].r)/2;
	if(r<=mid) update(2*s,l,r,x);
	else if(l>mid) update(2*s+1,l,r,x);
	else
		update(2*s,l,r,x),
			update(2*s+1,l,r,x);
}
ll query(int s,int x)
{
	if(a[s].l==a[s].r && a[s].l==x)
		return a[s].Max;
	pushdown(s);
	int mid=(a[s].l+a[s].r)/2;
	if(x<=mid) return query(2*s,x);
	else return query(2*s+1,x);
}
void addsolve()
{
	bulidtree(1,1,n,0);
	sort(add,add+la,cmp);
	rep(i,la)
	{
		int u=add[i].u,v=add[i].v;
		if(add[i].sign==0) update(1,add[i].v,n,add[i].w);
		else 
		   if(u==v)
		   ans[add[i].i]=0;
		   else
	   		   ans[add[i].i]=sum[v]-sum[u]-query(1,add[i].v);
	}
}
void delsolve()
{
	bulidtree(1,1,n,-inf);
	sort(del,del+lb,cmp);
	rep(i,lb)
	{
		int u=del[i].u,v=del[i].v;
		if(del[i].sign==0) update(1,v,u-1,del[i].w);
		else 
			if(u==v)
				ans[del[i].i]=0;
		   else
			ans[del[i].i]=sum[n]-sum[u]+sum[v]-query(1,del[i].v);
	}
}
int main()
{
	int u,v;
	ll w;
	sum[1]=0;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		repf(i,2,n)
			scanf("%lld",&w),
			sum[i]=sum[i-1]+w;
		la=lb=0;
		repf(i,1,m)
		{
			scanf("%d%d%lld",&u,&v,&w);
			if(u<v) add[la++].set(u,v,sum[v]-sum[u]-w,i,0);
			else if(u>v)  del[lb++].set(u,v,sum[n]-sum[u]+sum[v]-w,i,0);
		}
		scanf("%d",&t);
		repf(i,1,t)
		{
			scanf("%d%d",&u,&v);
			if(u<v) add[la++].set(u,v,0,i,1);
			else del[lb++].set(u,v,0,i,1);
		}
		memset(ans,0,sizeof(ans));
		addsolve();
		delsolve();
		repf(i,1,t) printf("%lld\n",ans[i]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡定的小Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值