社论:P14348 [JOISC 2019] 穿越时空 Bitaro / Bitaro, who Leaps through Time
Jordan_Pan · · 题解
0
被神秘双半群构造吓哭了,我怎么只会汤包了的无脑做法。(但是本质相同?)
qoj 代码长度倒四,但是两个
1
感性理解一下,走回头路一定是不优的。
然后就可以
不妨把询问分成
令
手动模拟以下这个过程,发现把整个值域从
如图,竖线为题目给的区间,横线为路径,其中红色的需要代价。在第四条竖线处,所有起点都被压缩到了一个点上。
于是可以考虑弹飞绵羊,对序列分块,修改时整块倒过来做区间加等差数列计算代价,复杂度大概是根号 log。
然后我们发现,在这个压成一个点的分界点之前的代价是好算的,就是走到区间交集;压成一个点之后的代价可以直接算这个点的走的代价。
于是我们在线段树上模拟这个过程。
2
具体地,对于节点
我们设计一个函数
线段树拆出来
于是现在只需要写出来 Pushup() 就做完这个题了。
这里我分了三类讨论:左子结点的区间交集为空(即已经能够压缩),左子结点的区间交集不为空并且左右子结点的
对于最后一种情况需要求出新的
所以复杂度为
3
反过来的部分把整个线段树复制了一遍,代码长度 4k。
:::info[代码]
#include<bits/stdc++.h>
constexpr int rSiz=1<<21;
char rBuf[rSiz],*p1=rBuf,*p2=rBuf;
#define gc() (p1==p2&&(p2=(p1=rBuf)+fread(rBuf,1,rSiz,stdin),p1==p2)?EOF:*p1++)
template<class T>void rd(T&x){
char ch=gc();
for(;ch<'0'||ch>'9';ch=gc());
for(x=0;ch>='0'&&ch<='9';ch=gc())
x=(x<<1)+(x<<3)+(ch^48);
}
constexpr int _=3e5+5,inf=2e9;
int n,q;
int C(int x,int l,int r){
if(x>r)return r;
else if(x<l)return l;
else return x;
}
#define mid ((l+r)>>1)
struct D1{
int a[_],b[_];
struct node{int l,r,pos,y;long long val;}t[_<<2];
long long calc(int p,node x){
return std::max(p-x.r,0)+(x.pos?std::max(C(p,x.l,x.r)-b[x.pos],0):0)+x.val;
}
void Pup(int x,int l,int r){
node ls=t[x<<1],rs=t[x<<1|1];
if(ls.pos){
t[x].l=ls.l;t[x].r=ls.r;t[x].pos=ls.pos;
if(rs.pos)t[x].y=rs.y;
else t[x].y=C(ls.y,rs.l,rs.r);
t[x].val=ls.val+calc(ls.y,rs);
}
else if(ls.r<rs.l||ls.l>rs.r){
t[x].l=ls.l;t[x].r=ls.r;
for(int y=(x<<1|1),L=mid+1,R=r;;){
if(L==R){t[x].pos=L;break;}
if(t[y<<1].r<ls.l||t[y<<1].l>ls.r)R=(L+R)>>1,y<<=1;
else{
t[x].l=std::max(t[x].l,t[y<<1].l);
t[x].r=std::min(t[x].r,t[y<<1].r);
L=((L+R)>>1)+1,y=y<<1|1;
}
}
int w=C(t[x].l,a[t[x].pos],b[t[x].pos]);
t[x].val=calc(w,rs);
if(rs.pos)t[x].y=rs.y;
else t[x].y=C(w,rs.l,rs.r);
}
else{
t[x].l=std::max(ls.l,rs.l);
t[x].r=std::min(ls.r,rs.r);
t[x].pos=rs.pos;t[x].y=rs.y;t[x].val=rs.val;
}
}
void Chg(int x,int l,int r,int w){
if(l==r)return t[x]={a[w],b[w],0,0,0},void();
if(w<=mid)Chg(x<<1,l,mid,w);
else Chg(x<<1|1,mid+1,r,w);
Pup(x,l,r);
}
int pos;long long ans;
void Qry(int x,int l,int r,int L,int R){
if(L<=l&&r<=R){
ans+=calc(pos,t[x]);
if(t[x].pos)pos=t[x].y;
else pos=C(pos,t[x].l,t[x].r);
return;
}
if(L<=mid)Qry(x<<1,l,mid,L,R);
if(R>mid)Qry(x<<1|1,mid+1,r,L,R);
}
void Upd(int x,int l,int r){
a[x]=l+n-x+1,b[x]=r+n-x;
Chg(1,1,n,x);
}
long long Ask(int l,int r,int x,int y){
x=x+n-l+1;y=y+n-r+1;
pos=x;ans=0;
Qry(1,1,n,l,r-1);
return ans+std::max(pos-y,0);
}
}D1;
struct D2{
int a[_],b[_];
struct node{int l,r,pos,y;long long val;}t[_<<2];
long long calc(int p,node x){
return std::max(p-x.r,0)+(x.pos?std::max(C(p,x.l,x.r)-b[x.pos],0):0)+x.val;
}
void Pup(int x,int l,int r){
node ls=t[x<<1],rs=t[x<<1|1];
if(ls.pos){
t[x].l=ls.l;t[x].r=ls.r;t[x].pos=ls.pos;
if(rs.pos)t[x].y=rs.y;
else t[x].y=C(ls.y,rs.l,rs.r);
t[x].val=ls.val+calc(ls.y,rs);
}
else if(ls.r<rs.l||ls.l>rs.r){
t[x].l=ls.l;t[x].r=ls.r;
for(int y=(x<<1|1),L=mid+1,R=r;;){
if(L==R){t[x].pos=L;break;}
if(t[y<<1].r<ls.l||t[y<<1].l>ls.r)R=(L+R)>>1,y<<=1;
else{
t[x].l=std::max(t[x].l,t[y<<1].l);
t[x].r=std::min(t[x].r,t[y<<1].r);
L=((L+R)>>1)+1,y=y<<1|1;
}
}
int w=C(t[x].l,a[t[x].pos],b[t[x].pos]);
t[x].val=calc(w,rs);
if(rs.pos)t[x].y=rs.y;
else t[x].y=C(w,rs.l,rs.r);
}
else{
t[x].l=std::max(ls.l,rs.l);
t[x].r=std::min(ls.r,rs.r);
t[x].pos=rs.pos;t[x].y=rs.y;t[x].val=rs.val;
}
}
void Chg(int x,int l,int r,int w){
if(l==r)return t[x]={a[w],b[w],0,0,0},void();
if(w<=mid)Chg(x<<1,l,mid,w);
else Chg(x<<1|1,mid+1,r,w);
Pup(x,l,r);
}
int pos;long long ans;
void Qry(int x,int l,int r,int L,int R){
if(L<=l&&r<=R){
ans+=calc(pos,t[x]);
if(t[x].pos)pos=t[x].y;
else pos=C(pos,t[x].l,t[x].r);
return;
}
if(L<=mid)Qry(x<<1,l,mid,L,R);
if(R>mid)Qry(x<<1|1,mid+1,r,L,R);
}
void Upd(int x,int l,int r){
a[x]=l+n-x+1,b[x]=r+n-x;
Chg(1,1,n,x);
}
long long Ask(int l,int r,int x,int y){
x=x+n-l+1;y=y+n-r+1;
pos=x;ans=0;
Qry(1,1,n,l,r-1);
return ans+std::max(pos-y,0);
}
}D2;
int main(){
rd(n),rd(q);
for(int i=1,l,r;i<n;++i){
rd(l),rd(r);
D1.Upd(i,l,r);
D2.Upd(n-i,l,r);
}
for(int op,x,y,l,r;q;--q){
rd(op);
if(op&1){
rd(x),rd(l),rd(r);
D1.Upd(x,l,r);
D2.Upd(n-x,l,r);
}
else{
rd(l),rd(x),rd(r),rd(y);
long long ans;
if(l==r)ans=std::max(x-y,0);
else if(l<r)ans=D1.Ask(l,r,x,y);
else ans=D2.Ask(n-l+1,n-r+1,x,y);
printf("%lld\n",ans);
}
}
}
:::