比赛的时候感觉这道题可以写,在那里分析了很久,就对于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;
}