佣神给的思路
线段树预处理每一个road的起始和结束时间
然后排序按天数扫描,每天看有没有需要增加新路,看有没有需要关闭路
因为是排好序的,所以不会重复扫
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=600100;
int n,ans,m,a[N];
struct node {
int l,r,id;
node () { }
node(int x,int y,int z){l=x;r=y;id=z;}
}b[N],c[N];
inline bool cmp1(node a,node b){return a.l<b.l;}
inline bool cmp2(node a,node b){return a.r<b.r;}
struct linetree{
#define lc (t<<1)
#define rc (t<<1^1)
#define mid (l[t]+r[t]>>1)
int l[N],r[N],ma[N],mi[N],M,ta[N],ti[N];
inline void build(int n){
M=1; while(M<n)M<<=1; M--;
memset(ma, 0 ,sizeof(ma));
memset(mi,INF,sizeof(mi));
memset(ta, 0 ,sizeof(ta));
memset(ti,INF,sizeof(ti));
for (int i=1+M;i<=M*2+1;i++)l[i]=r[i]= i-M ;
for (int t=M;t>=1;t--)l[t]=l[lc],r[t]=r[rc];
}
inline void down(int t){
if (t>M)return ;//leaf node
ma[lc]=max(ma[lc],ta[t]);
ma[rc]=max(ma[rc],ta[t]);
ta[lc]=max(ta[lc],ta[t]);
ta[rc]=max(ta[rc],ta[t]);
ta[t] = 0;
mi[lc]=min(mi[lc],ti[t]);
mi[rc]=min(mi[rc],ti[t]);
ti[lc]=min(ti[lc],ti[t]);
ti[rc]=min(ti[rc],ti[t]);
ti[t] = INF;
}
inline void maintain(int t){
ma[t]=max(ma[lc],ma[rc]);
mi[t]=min(mi[lc],mi[rc]);
}
inline void tag(int t,int x){
ma[t]=max(ma[t],x);
mi[t]=min(mi[t],x);
ta[t]=max(ta[t],x);
ti[t]=min(ti[t],x);
}
void change(int t,int L,int R,int x){
if (L<=l[t]&&r[t]<=R){tag(t,x);return;}
down(t);
if (L<=mid)change(lc,L,R,x);
if (mid< R)change(rc,L,R,x);
maintain(t);
}
void query(int t){
if (t>M){//leaf node
b[t-M]=c[t-M]=node(mi[t],ma[t],t-M);
return ;
}
down(t);
query(lc);
query(rc);
maintain(t);
}
}T;
int main(){
//freopen("fuck.in","r",stdin);
int l,r;
while (scanf("%d%d",&n,&m)==2){
for (int i=1;i<n;i++)scanf("%d",&a[i]);
T.build(n-1) ;
for (int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
if(l>=r) swap(l,r) ;
T.change(1,l,r-1,i);
}
T.query(1);
sort(b+1, b+n, cmp1);
sort(c+1, c+n, cmp2);
int x=1, y=1, ans=0 ;
for (int i=1;i<=m;i++){
for (; x<n &&b[x].l<=i;x++)
if(b[x].l<=b[x].r)ans+=a[b[x].id];
for (; y<n &&c[y].r< i;y++)
if(c[y].l<=c[y].r)ans-=a[c[y].id];
printf("%d
" , ans);
}
}
return 0;
}
多校训练结束啦,闷声滚大粗了
我好菜啊
其实,,因为是单点查询,而且所有点顺序查一次就行了
所以,,不需要tag,不需要maintain
新姿势
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=600100;
int n,ans,m,a[N];
struct node {
int l,r,id;
node () { }
node(int x,int y,int z){l=x;r=y;id=z;}
}b[N],c[N];
inline bool cmp1(node a,node b){return a.l<b.l;}
inline bool cmp2(node a,node b){return a.r<b.r;}
struct linetree{
#define lc (t<<1)
#define rc (t<<1^1)
#define mid (l[t]+r[t]>>1)
int l[N],r[N],ma[N],mi[N],M;
inline void build(int n){
M=1; while(M<n)M<<=1; M--;
memset(ma, 0 ,sizeof(ma));
memset(mi,INF,sizeof(mi));
for (int i=1+M;i<=M*2+1;i++)l[i]=r[i]= i-M ;
for (int t=M;t>=1;t--)l[t]=l[lc],r[t]=r[rc];
}
inline void down(int t){
if (t>M)return ;//leaf node
ma[lc]=max(ma[lc],ma[t]);
ma[rc]=max(ma[rc],ma[t]);
mi[lc]=min(mi[lc],mi[t]);
mi[rc]=min(mi[rc],mi[t]);
}
inline void tag(int t,int x){
ma[t]=max(ma[t],x);
mi[t]=min(mi[t],x);
}
void change(int t,int L,int R,int x){
if (L<=l[t]&&r[t]<=R){tag(t,x);return;}//in
down(t);
if (L<=mid)change(lc,L,R,x);
if (mid< R)change(rc,L,R,x);
}
void query(int t){
if (t>M){//leaf node
b[t-M]=c[t-M]=node(mi[t],ma[t],t-M);
return ;
}
down(t);
query(lc);
query(rc);
}
}T;
int main(){
//freopen("fuck.in","r",stdin);
int l,r;
while (scanf("%d%d",&n,&m)==2){
for (int i=1;i<n;i++)scanf("%d",&a[i]);
T.build(n-1) ;
for (int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
if(l>=r) swap(l,r) ;
T.change(1,l,r-1,i);
}
T.query(1);
sort(b+1, b+n, cmp1);
sort(c+1, c+n, cmp2);
int x=1, y=1, ans=0 ;
for (int i=1;i<=m;i++){
for (; x<n &&b[x].l<=i;x++)
if(b[x].l<=b[x].r)ans+=a[b[x].id];
for (; y<n &&c[y].r< i;y++)
if(c[y].l<=c[y].r)ans-=a[c[y].id];
printf("%d
" , ans);
}
}
return 0;
}