HDU 5861 Road 解题报告

题目链接:Here!

题目大意:在一条路上有n座村庄,每天给定两个村庄之间的路必须是畅通的,开启道路的费用就是路的权值,每条道路只能开,关各一次,问从开始到每一天的费用最小是多少。

题目思路:利用线段树处理出每一条路开启的时间段,将所有的开启日期和关闭日期混合在一起排序,然后从1-m枚举日期,如果当前日期是某一条线段的开启日期,则答案加上该线段的权值,若当前日期是某一条线段的关闭日期,则答案减去该线段的权值。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <list>
#include <deque>
#define LL long long
#define INF 0x3f3f3f3f
#define PII pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define lowbit(x) (x&(-x))

using namespace std;
const int N = 200005 ;
vector<pair<int,PII> >v;
int val[N];
struct Node{
    int l,r;
    int st,en;
};
struct Tree{
    Node a[N<<2];
    void Buildtree(int i,int left,int right)
    {
        a[i].l=left;
        a[i].r=right;
        a[i].st=a[i].en=0;

        if(left==right)
            return ;

        int mid=(left+right)>>1;
        Buildtree(i<<1,left,mid);
        Buildtree(i<<1|1,mid+1,right);
    }
    void Update(int i,int left,int right,int date)
    {
        if(a[i].l>=left&&a[i].r<=right)
        {
            if(a[i].st==0)a[i].st=a[i].en=date;
            else a[i].en=date;
            return ;
        }

        int mid=(a[i].l+a[i].r)>>1;
        if(left<=mid)Update(i<<1,left,right,date);
        if(mid<right)Update(i<<1|1,left,right,date);
    }
    void PushDown(int i)
    {
        if(a[i].st)
        {
            if(a[i<<1].st)
            {
                a[i<<1].st=min(a[i<<1].st,a[i].st);
                a[i<<1].en=max(a[i<<1].en,a[i].en);
            }
            else
            {
                a[i<<1].st=a[i].st;
                a[i<<1].en=a[i].en;
            }
            if(a[i<<1|1].st)
            {
                a[i<<1|1].st=min(a[i<<1|1].st,a[i].st);
                a[i<<1|1].en=max(a[i<<1|1].en,a[i].en);
            }
            else
            {
                a[i<<1|1].st=a[i].st;
                a[i<<1|1].en=a[i].en;
            }
            a[i].st=a[i].en=0;
        }
    }
    void tr(int i)
    {
        if(a[i].l==a[i].r)
        {
            v.pb(mp(val[a[i].l],mp(a[i].st,a[i].en)));
            return ;
        }

        PushDown(i);
        tr(i<<1);
        tr(i<<1|1);
    }
}seg;

vector<PII>vt;

int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m)==2)
    {
        v.clear();
        vt.clear();
        seg.Buildtree(1,1,n);
        for(int i=1;i<n;i++)
            scanf("%d",&val[i]);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            if(x>y)swap(x,y);y--;
            seg.Update(1,x,y,i);
        }
        seg.tr(1);
        for(int i=0;i<v.size();i++)
            vt.pb(mp(v[i].se.fi,v[i].fi)),vt.pb(mp(v[i].se.se+1,-v[i].fi));
        sort(vt.begin(),vt.end());
        int st=0,ans=0;
        for(int i=1;i<=m;i++)
        {
            while(st<vt.size()&&vt[st].fi<=i)ans+=vt[st++].se;
            printf("%d\n",ans);
        }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值