多校那么多道线段树就没有一道在比赛时写出来的。
根据题意,每一条公路只能开一次。所以对于每一条公路,第一开了之后,只有当最后一次使用完成之后才可以关闭。所以,我们要预处理出每条公路第一次使用和最后一次使用的时间。这里我直接用线段树维护每一条公路的最迟和最早使用时间。之后,本来自己想的是在以天数建一棵线段树,把每一条公路的最早和最迟使用区间内的每一点都更新值,最后在查询得出答案。看了人家的博客后,发现可以在原来的树上直接做,将得到的时间排序,然后最早时间线段树对应点加上费用,最迟时间之后线段树上对应点点减去费用。每一天的答案都在sum[1]上。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200000+10;
struct node
{
int x,t,f;
} p[4*N];
ll sum[4*N+10],a[N];
int tot,n,m,mi[4*N+10],ma[4*N+10];
int l[N],r[N];
int cmp(node n1,node n2)
{
if(n1.t==n2.t)
return n1.f<n2.f;
else
return n1.t<n2.t;
}
void down(int o)
{
if(mi[o]!=-1)
{
if(mi[o*2]==-1)
mi[o*2]=mi[o];
else
mi[o*2]=min(mi[o],mi[o*2]);
if(mi[o*2+1]==-1)
mi[o*2+1]=mi[o];
else
mi[o*2+1]=min(mi[o],mi[o*2+1]);
}
if(ma[o]!=-1)
{
if(ma[o*2]==-1)
ma[o*2]=ma[o];
else
ma[o*2]=max(ma[o],ma[o*2]);
if(ma[o*2+1]==-1)
ma[o*2+1]=ma[o];
else
ma[o*2+1]=max(ma[o],ma[o*2+1]);
}
mi[o]=ma[o]=-1;
}
void update(int o,int l,int r,int x,int y,int v)
{
//printf("%d %d\n",l,r);
int mid=l+(r-l)/2;
if(x<=l&&y>=r)
{
if(mi[o]==-1)
mi[o]=v;
else
mi[o]=min(mi[o],v);
if(ma[o]==-1)
ma[o]=v;
else
ma[o]=max(ma[o],v);
}
else
{
down(o);
if(x<=mid) update(o*2,l,mid,x,y,v);
if(y>mid) update(o*2+1,mid+1,r,x,y,v);
if(mi[o*2]==mi[o*2+1]) mi[o]=mi[o*2];
else mi[o]=-1;
if(ma[o*2]==ma[o*2+1]) ma[o]=ma[o*2];
else ma[o]=-1;
}
}
void query(int o,int l,int r)
{
if(l==r)
{
if(mi[o]!=-1)
{
node tmp;
tmp.x=l;
tmp.t=mi[o];
tmp.f=1;
p[tot]=tmp;
tot++;
}
if(ma[o]!=-1)
{
node tmp;
tmp.x=l;
tmp.t=ma[o]+1;
tmp.f=0;
p[tot]=tmp;
tot++;
}
//printf(" %lld %lld\n",mi[o],ma[o]);
}
else
{
down(o);
int mid=l+(r-l)/2;
query(o*2,l,mid);
query(o*2+1,mid+1,r);
}
}
void updatesum(int o,int l,int r,int x,ll v)
{
if(l==r)
{
sum[o]+=v;
// printf("%lld\n",sum[o]);
}
else
{
int mid=l+(r-l)/2;
if(x<=mid) updatesum(o*2,l,mid,x,v);
else updatesum(o*2+1,mid+1,r,x,v);
sum[o]=sum[o*2]+sum[o*2+1];
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1; i<n; i++) scanf("%lld",&a[i]);
memset(sum,0,sizeof(sum));
memset(ma,0xff,sizeof(ma));
memset(mi,0xff,sizeof(mi));
for(int i=1; i<=m; i++)
{
scanf("%d%d",&l[i],&r[i]);
if(l[i]>r[i]) swap(l[i],r[i]);
r[i]--;
update(1,1,n-1,l[i],r[i],i);
}
tot=0;
query(1,1,n-1);
sort(p,p+tot,cmp);
//printf("%d\n",tot);
int j=0;
for(int i=1; i<=m; i++)
{
while(p[j].t==i)
{
if(p[j].f==0) updatesum(1,1,n-1,p[j].x,-a[p[j].x]);
else updatesum(1,1,n-1,p[j].x,a[p[j].x]);
j++;
if(j>=tot) break;
}
printf("%lld\n",sum[1]);
}
}
return 0;
}