ZOJ 3724 Delivery(离线线段树)

题意:N个点,对于每个点i,都有一条连向i+1的有向边,另外有M条其他的有向边,有Q个询问(U,V)求U到V的最短路。

当U<V的时候,很好处理查询下U到V范围内哪条边节省的时间多就可以了。U>V的处理方法很相似。分两种情况,分别离线处理一次就可以了。

//#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

#define INF (1LL<<60)
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))

const int N=100005;

LL A[N],sum[N],ans[N*2];

struct OP
{
    int st,ed,w;
    OP(){}
    OP(int st,int ed,int w) :
        st(st),ed(ed),w(w) {}
};
bool cmpST(const OP &A,const OP &B)
{
    return A.st<B.st;
}
bool cmpED(const OP &A,const OP &B)
{
    return A.ed<B.ed;
}

vector<OP> QA,QB;
vector<OP> RA,RB;

struct Segtree
{
    LL mx[N*4];
    void PushUp(int ind)
    {
        mx[ind]=max(mx[LL(ind)],mx[RR(ind)]);
    }
    void build(int lft,int rht,int ind)
    {
        mx[ind]=-INF;
        if(lft!=rht)
        {
            int mid=MID(lft,rht);
            build(lft,mid,LL(ind));
            build(mid+1,rht,RR(ind));
        }
    }
    void updata(int pos,LL valu,int lft,int rht,int ind)
    {
        if(lft==rht) mx[ind]=max(mx[ind],valu);
        else
        {
            int mid=MID(lft,rht);
            if(pos<=mid) updata(pos,valu,lft,mid,LL(ind));
            else updata(pos,valu,mid+1,rht,RR(ind));
            PushUp(ind);
        }
    }
    LL query(int st,int ed,int lft,int rht,int ind)
    {
        if(st<=lft&&rht<=ed) return mx[ind];
        else
        {
            LL mx1=-INF,mx2=-INF;
            int mid=MID(lft,rht);
            if(st<=mid) mx1=query(st,ed,lft,mid,LL(ind));
            if(ed> mid) mx2=query(st,ed,mid+1,rht,RR(ind));
            return max(mx1,mx2);
        }
    }
}seg;

int main()
{
   // freopen("in.txt","r",stdin);

    int n,m,Q;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        QA.clear(); QB.clear();
        RA.clear(); RB.clear();

        int len1=0,len2=0;

        sum[1]=0;
        for(int i=2;i<=n;i++) scanf("%lld",&A[i]);
        for(int i=2;i<=n;i++) sum[i]=A[i]+sum[i-1];

        for(int i=0;i<m;i++)
        {
            int a,b,c; scanf("%d%d%d",&a,&b,&c);
            if(a<b)
            {
                if(sum[b]-sum[a]<c) continue;
                else RA.push_back(OP(a,b,(sum[b]-sum[a])-c));
            }
            else
            {
                LL tmp=sum[b]+(sum[n]-sum[a]);
                RB.push_back(OP(b,a,tmp-c));
            }
        }

        scanf("%d",&Q);
        for(int i=0;i<Q;i++)
        {
            int a,b; scanf("%d%d",&a,&b);
            if(a<b) QA.push_back(OP(a,b,i));
            else if(a>b) QB.push_back(OP(b,a,i));
            else ans[i]=0;
        }

        seg.build(1,n,1);
        sort(QA.begin(),QA.end(),cmpED);
        sort(RA.begin(),RA.end(),cmpED);

        len1=(int)QA.size();
        len2=(int)RA.size();
        int ind=0;

        for(int i=0;i<len1;i++)
        {
            while(ind<len2&&RA[ind].ed<=QA[i].ed)
            {
                seg.updata(RA[ind].st,RA[ind].w,1,n,1);
                ind++;
            }
            LL tmp=seg.query(QA[i].st,QA[i].ed,1,n,1);
            tmp=max(tmp,0LL);
            ans[QA[i].w]=sum[QA[i].ed]-sum[QA[i].st]-tmp;
        }

        seg.build(1,n,1);
        sort(QB.begin(),QB.end(),cmpST);
        sort(RB.begin(),RB.end(),cmpST);

        len1=(int)QB.size();
        len2=(int)RB.size();
        ind=0;

        for(int i=0;i<len1;i++)
        {
            while(ind<len2&&RB[ind].st<=QB[i].st)
            {
                seg.updata(RB[ind].ed,RB[ind].w,1,n,1);
                ind++;
            }
            LL tmp=seg.query(QB[i].ed,n,1,n,1);
            ans[QB[i].w]=sum[n]-(sum[QB[i].ed]-sum[QB[i].st])-tmp;
        }
        for(int i=0;i<Q;i++) printf("%lld\n",ans[i]);
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值