zoukankan      html  css  js  c++  java
  • 【LOJ3038】「JOISC 2019 Day3」穿越时空 Bitaro(线段树)

    点此看题面

    • 给定一条长度为(n)的链,你只能在(L_isim R_i-1)间的某一时刻从(i)出发走到(i+1),走每条边都花费(1)单位时间。
    • 一次操作可以让时间倒流(1)秒。
    • (q)次操作,分为两种:修改某一条边的(L,R);询问在(B)时刻从(A)出发,在(D)时刻之前到达(C)至少需要操作多少次。
    • (n,qle3 imes10^5)

    时间“静止”

    考虑我们每走一步时间会加(1),这是一个挺烦人的条件。

    对于从右向左的询问,我们只要之后把整个序列翻转一下另做一次就好了,因此可以认为所有询问都是从左向右的。

    然后我们把每个(L_i,R_i)都减去(i),这样一来相当于让时间“静止”了。

    区间的合并

    考虑连续经过两个区间([l_1,r_1],[l_2,r_2])

    如果([l_1,r_1]cap[l_2,r_2] ot=emptyset),那么其实就等价于经过一个区间([l_1,r_1]cap[l_2,r_2])

    否则,如果(r_1<l_2)则必然会先凝聚到(r_1)一个点然后走到(l_2),如果(l_1>r_2)则先凝聚到(l_1)然后走到(r_2),且从此我们都将是一个点。

    所以实际上只有两种情况,分别可以用一个二元组((l,r))(区间([l,r]))和一个三元组((x,y,v))(先凝聚成(x)进入,最后变成(y),一共操作了(v)次)。

    由于这个东西满足结合律,加上有单点修改,我们选择线段树维护。

    询问时只要求出(Asim C-1)的等价元组,然后在前后分别加上((B-A,B-A))((D-C,D-C))两个二元组即可。

    代码:(O(nlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 300000
    #define LL long long
    using namespace std;
    int n,Qt,L[N+5],R[N+5],l[N+5],r[N+5];LL ans[N+5];struct Q {int op,A,B,C,D;}q[N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[30],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    struct Data
    {
    	int x,y;LL v;I Data(CI a=0,CI b=0,Con LL& c=-1):x(a),y(b),v(c){}
    	I friend Data operator + (Con Data& A,Con Data& B)//元组的合并
    	{
    		if(~A.v&&~B.v) return Data(A.x,B.y,A.v+B.v+max(A.y-B.x,0));//三元组合并
    		if(~A.v) return Data(A.x,max(min(A.y,B.y),B.x),A.v+max(A.y-B.y,0));//三元组+二元组
    		if(~B.v) return Data(min(max(A.x,B.x),A.y),B.y,B.v+max(A.x-B.x,0));//二元组+三元组
    		if(max(A.x,B.x)<=min(A.y,B.y)) return Data(max(A.x,B.x),min(A.y,B.y),-1);//二元组合并:存在交集
    		return A.y<B.x?Data(A.y,B.x,0):Data(A.x,B.y,A.x-B.y);//不存在交集,变成三元组
    	}
    };
    class SegmentTree
    {
    	private:
    		#define PT CI l=1,CI r=n-1,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		#define PU(x) (V[x]=V[x<<1]+V[x<<1|1])
    		Data V[N<<2];
    	public:
    		I void Bd(PT)
    		{
    			if(l==r) return (void)(V[rt]=Data(::l[l],::r[l]));RI mid=l+r>>1;Bd(LT),Bd(RT),PU(rt);
    		}
    		I void U(CI x,Con Data& v,PT)//单点修改
    		{
    			if(l==r) return (void)(V[rt]=v);RI mid=l+r>>1;x<=mid?U(x,v,LT):U(x,v,RT),PU(rt);
    		}
    		I Data Q(CI L,CI R,PT)//区间查询
    		{
    			if(L<=l&&r<=R) return V[rt];RI mid=l+r>>1;if(R<=mid) return Q(L,R,LT);
    			if(L>mid) return Q(L,R,RT);return Q(L,mid,LT)+Q(mid+1,R,RT);
    		}
    }S;
    I void Solve()
    {
    	if(n==1) return;RI i;for(i=1;i^n;++i) l[i]=L[i]-i,r[i]=R[i]-1-i;S.Bd();//特判n=1;给L,R减去i使时间静止
    	for(i=1;i<=Qt;++i) q[i].op==1?(S.U(q[i].A,Data(q[i].B-q[i].A,q[i].C-1-q[i].A)),0)//单点修改
    		:q[i].A<q[i].C&&(ans[i]=(Data(q[i].B-q[i].A,q[i].B-q[i].A,-1)+S.Q(q[i].A,q[i].C-1)+Data(q[i].D-q[i].C,q[i].D-q[i].C)).v);//区间查询,前后加上两个二元组
    }
    int main()
    {
    	RI i;for(read(n),read(Qt),i=1;i^n;++i) read(L[i]),read(R[i]);
    	for(i=1;i<=Qt;++i) read(q[i].op),read(q[i].A),read(q[i].B),read(q[i].C),q[i].op==2&&(read(q[i].D),0);
    	for(Solve(),reverse(L+1,L+n),reverse(R+1,R+n),i=1;i<=Qt;++i) q[i].op==1?q[i].A=n-q[i].A:(q[i].A=n-q[i].A+1,q[i].C=n-q[i].C+1);//翻转
    	for(Solve(),i=1;i<=Qt;++i) q[i].op==2&&(writeln(q[i].A^q[i].C?ans[i]:max(q[i].B-q[i].D,0)),0);return clear(),0;//输出前特判单点
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    解决git推不上去1
    django中CBV源码分析
    Form和ModelForm组件
    jquery操作cookie
    django中的中间件
    django中ORM中锁和事务
    django_ajax
    docker安装jenkins 容器,集成python环境
    支付宝第三方支付
    redis基本使用
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/LOJ3038.html
Copyright © 2011-2022 走看看