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 次操作,每次操作分为三种类型:
- 0,l,r:询问从第 l l l 个火车站开始坐车,是否可以依次经过中途的火车站,直到 r r r 下车
- 1,i,w:修改 c o s t [ i ] = w cost[i]=w cost[i]=w
- 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(线段树区间合并)的主要内容,如果未能解决你的问题,请参考以下文章