[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号