[JOISC 2019 Day3]穿越时空 Bitaro
穿越时空 Bitaro
题解
首先应该很容易想到将点
i
i
i处的时间区间减去
i
i
i,这样就可以保证我们得时间前行转化成直线。
我们可以将转化后的前行的
x
−
t
x-t
x−t图画出来,很明显,我们得最优策略是先一直直走,遇到不能走时再调整到最近的第一个能走的时间。
但由于原询问要求处理代修改的情况与区间查询,我们很容易就想到了线段树。
对于每一个区间,我们可以得到一个三元组
(
L
′
,
R
′
,
c
o
s
t
)
(L',R',cost)
(L′,R′,cost),表示时间为
L
′
L'
L′时进入区间,为
R
′
R'
R′时出区间,消耗为
c
o
s
t
cost
cost。
对于合并三元组时,需要判断两个三元组的时间区间
(
L
′
,
R
′
)
(L',R')
(L′,R′)的对应关系。
若
R
′
′
<
L
′
R''<L'
R′′<L′,需要停会再走,这个阶段是不会增加能量消耗的。
但对于
R
′
′
>
L
′
R''>L'
R′′>L′的部分,需要向前回溯。
但由于实际操作中,开始的时间可能是一个区间,所以我们维护的其实是一个四元组。
由于开始的地方与结束的地方的大小关系是不定的,既有可能从前往后,又有可能从后往前,所以我们需要维护前缀后缀两棵线段树。
时间复杂度 O ( ( n + q ) l o g n ) O\left((n+q)log\, n\right) O((n+q)logn)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define MAXN 300005
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const int mo=1e9+7;
const int INF=0x7f7f7f7f;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,q;LL L[MAXN],R[MAXN];
struct tree{
LL l,r,x,y;
friend tree operator + (const tree &x,const tree &y){
tree res;
res.l=max(y.l,min(y.r,x.l));
res.r=min(y.r,max(y.l,x.r));
res.x=x.l<x.r?y.x>x.r?x.x:max(y.x,x.l):x.x;
res.y=x.y+y.y+max(x.l-y.x,0LL);
return res;
}
};
struct range{LL st,ed;};
class segmentTree{
private:
tree tr[MAXN<<2];
void updata(int rt){tr[rt]=tr[rt<<1]+tr[rt<<1|1];}
public:
range s[MAXN];
void insert(int rt,int id){tr[rt]=(tree){s[id].st-id,s[id].ed-id-1LL,s[id].ed-id-1LL,0LL};}
void build(int rt,int l,int r){
if(l==r){insert(rt,l);return ;}int mid=l+r>>1;
build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);updata(rt);
}
void modify(int rt,int l,int r,int ai,LL wl,LL wr){
if(l==r){s[l]=(range){wl,wr};insert(rt,ai);return ;}
int mid=l+r>>1;
if(ai<=mid)modify(rt<<1,l,mid,ai,wl,wr);
else modify(rt<<1|1,mid+1,r,ai,wl,wr);
updata(rt);
}
tree query(int rt,int l,int r,int al,int ar){
if(al<=l&&r<=ar)return tr[rt];int mid=l+r>>1;tree res;
if(ar<=mid)return query(rt<<1,l,mid,al,ar);
if(al>mid)return query(rt<<1|1,mid+1,r,al,ar);
return query(rt<<1,l,mid,al,ar)+query(rt<<1|1,mid+1,r,al,ar);
}
LL work(int a,LL b,int c,LL d){
LL res=0;b-=a;d-=c;if(a==c)return max(b-d,0LL);
tree tmp=query(1,1,n-1,a,c-1);res=tmp.y+max(b-tmp.x,0LL);
b=max(b,tmp.l);b=min(b,tmp.r);return res+max(b-d,0LL);
}
}Pre,Suf;
signed main(){
read(n);read(q);
for(int i=1;i<n;i++)read(L[i]),read(R[i]),Pre.s[i]=(range){L[i],R[i]},Suf.s[n-i]=(range){L[i],R[i]};
if(n>1)Pre.build(1,1,n-1),Suf.build(1,1,n-1);
for(int i=1;i<=q;i++){
int typ;read(typ);
if(typ==1){
LL p,s,e;read(p);read(s);read(e);
Pre.modify(1,1,n-1,p,s,e);Suf.modify(1,1,n-1,n-p,s,e);
}
else{
int a,c;LL b,d;read(a);read(b);read(c);read(d);
if(a<c)printf("%lld\n",Pre.work(a,b,c,d));
else printf("%lld\n",Suf.work(n-a+1,b,n-c+1,d));
}
}
return 0;
}

浙公网安备 33010602011771号