题目链接: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;
}