2021牛客多校1 - Journey among Railway Stations(线段树区间合并)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客多校1 - Journey among Railway Stations(线段树区间合并)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个长度为 n n n 的序列表示火车站,每个火车站都有两个属性 [ u , v ] [u,v] [u,v],表示在站时间。相邻两个火车站之间有一个距离,即从第 i i i 个火车站到第 i + 1 i+1 i+1 个火车站需要花费 c o s t [ i ] cost[i] cost[i] 个单位的时间。现在需要完成 m m m 次操作,每次操作分为三种类型:

  1. 0,l,r:询问从第 l l l 个火车站开始坐车,是否可以依次经过中途的火车站,直到 r r r 下车
  2. 1,i,w:修改 c o s t [ i ] = w cost[i]=w cost[i]=w
  3. 2,i,p,q:修改 [ u [ i ] , v [ i ] ] [u[i],v[i]] [u[i],v[i]] [ p , q ] [p,q] [p,q]

题目分析:官方题解:

官方题解在实现方面已经说得很清楚了,但我还是有点疑惑,设 a a a 为左区间, b b b 为右区间, a n s ans ans 为合并后的区间,为什么合并的代码是:

if(a.ok&&b.ok&&a.maxu<=b.minv) {
ans.ok=true;
} else {
	ans.ok=false;
}

而不是:

if(a.ok&&b.ok&&ans.maxu<=ans.minv) {
	ans.ok=true;
} else {
	ans.ok=false;
}

想了大概有小一会吧,终于给想明白了,其实观察题解给出的方程不难看出,我们需要的是 u ′ u' u 的前缀最大值和 v ′ v' v 进行比较。换句话说,我们想要知道 l l l 能否到达 r r r,实际上需要用 m a x ( u ′ [ l ] , u ′ [ l + 1 ] , . . . , u ′ [ r ] ) max(u'[l],u'[l+1],...,u'[r]) max(u[l],u[l+1],...,u[r]) 去和 v ′ [ r ] v'[r] v[r] 进行比较,如果在合并后再去比较的话,可能最小的这个 v ′ v' v,实际上就变成 v ′ [ x ] v'[x] v[x] 了,这里的 x < r x<r x<r,那么这样的比较其实是没有意义的

所以在合并的时候,需要严格控制 u ′ [ i ] u'[i] u[i] 的取值范围是左区间,同时 v ′ [ i ] v'[i] v[i] 的取值范围是右区间,这样就可以正确的合并了

代码:

// Problem: Journey among Railway Stations
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11166/J
// Memory Limit: 1048576 MB
// Time Limit: 6000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
	if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
LL u[N],v[N],cost[N],sum[N];
struct Node {
	int l,r;
	LL maxu,minv,lazy;
	bool ok;
}tree[N<<2];
void merge(Node &ans,Node a,Node b) {
	ans.l=a.l,ans.r=b.r;
	ans.maxu=max(a.maxu,b.maxu);
	ans.minv=min(a.minv,b.minv);
	if(a.ok&&b.ok&&a.maxu<=b.minv) {
		ans.ok=true;
	} else {
		ans.ok=false;
	}
}
void pushup(int k) {
	merge(tree[k],tree[k<<1],tree[k<<1|1]);
}
void change(int k,LL val) {
	tree[k].lazy+=val;
	tree[k].maxu+=val;
	tree[k].minv+=val;
}
void pushdown(int k) {
	if(tree[k].lazy) {
		LL lz=tree[k].lazy;
		tree[k].lazy=0;
		change(k<<1,lz);
		change(k<<1|1,lz);
	}
}
void build(int k,int l,int r) {
	tree[k]={l,r};
	if(l==r) {
		tree[k].maxu=u[l]+sum[l];
		tree[k].minv=v[l]+sum[l];
		tree[k].ok=true;
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}
void update(int k,int l,int r,int val,int flag) {
	if(tree[k].l>r||tree[k].r<l) {
		return;
	}
	if(tree[k].l>=l&&tree[k].r<=r) {
		if(flag==1) {//change u
			tree[k].maxu+=val;
		} else if(flag==2) {//change v
			tree[k].minv+=val;
		} else if(flag==3) {//change cost
			change(k,val);
		}
		return;
	}
	pushdown(k);
	update(k<<1,l,r,val,flag);
	update(k<<1|1,l,r,val,flag);
	pushup(k);
}
Node query(int k,int l,int r) {
	if(tree[k].l>=l&&tree[k].r<=r) {
		return tree[k];
	}
	pushdown(k);
	int mid=(tree[k].l+tree[k].r)>>1;
	if(r<=mid) {
		return query(k<<1,l,r);
	} else if(l>mid) {
		return query(k<<1|1,l,r);
	} else {
		Node ans;
		merge(ans,query(k<<1,l,r),query(k<<1|1,l,r));
		return ans;
	}
}
int main()
{
#ifndef ONLINE_JUDGE
//	freopen("data.in.txt","r",stdin);
//	freopen("data.out.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int w;
	cin>>w;
	while(w--) {
		int n;
		read(n);
		for(int i=1;i<=n;i++) {
			read(u[i]);
		}
		for(int i=1;i<=n;i++) {
			read(v[i]);
		}
		for(int i=1;i<n;i++) {
			read(cost[i]);
		}
		sum[n]=0;
		for(int i=n-1;i>=1;i--) {
			sum[i]=cost[i]+sum[i+1];
		}
		build(1,1,n);
		int q;
		read(q);
		while(q--) {
			int op;
			read(op);
			if(op==0) {
				int l,r;
				read(l),read(r);
				puts(query(1,l,r).ok?"Yes":"No");
			} else if(op==1) {
				int i,w;
				read(i),read(w);
				update(1,1,i,w-cost[i],3);
				cost[i]=w;
			} else if(op==2) {
				int i,p,q;
				read(i),read(p),read(q);
				update(1,i,i,p-u[i],1);
				update(1,i,i,q-v[i],2);
				u[i]=p,v[i]=q;
			}
		}
	}
	return 0;
}

以上是关于2021牛客多校1 - Journey among Railway Stations(线段树区间合并)的主要内容,如果未能解决你的问题,请参考以下文章

2021牛客多校8 D.OR(位运算)

2021牛客多校5 B Boxes

2021牛客多校8 D OR

2021牛客多校5 H Holding Two

2021牛客多校2 C Draw Grids

2021牛客多校9 - Cells(推公式+NTT)