此题不提供链接
题目描述
namespace_std 是一名 Minecraft 玩家。
这天,他开 op 拿到了无数的混凝土粉末,准备扔进一个世界里。
这个世界可以视为一个长度为 n n n,宽度为 1,高度无限的平面,其中 ( x , 0 ) (x,0) (x,0) 的位置为基岩,其上方均为空气。
namespace_std 会进行两种操作共计 q q q 次:
1 l r h
:在区间
[
l
,
r
]
[l,r]
[l,r] 内每个横坐标上方无限高处扔下
h
h
h 块第
x
x
x 种混凝土粉末,其中
x
x
x 是这次操作的序号。混凝土被扔下后会一直下落直到落到另一个方块上方。
2 x y
:查询
(
x
,
y
)
(x,y)
(x,y) 位置是哪种混凝土。如果
(
x
,
y
)
(x,y)
(x,y) 上此时是空气输出 0。
数据规模与约定: 1 ≤ n , q ≤ 1 0 6 , 1 ≤ h ≤ 1 0 9 , 1 ≤ y ≤ 1 0 18 1\le n,q\le 10^6,1\le h\le 10^9,1\le y\le 10^{18} 1≤n,q≤106,1≤h≤109,1≤y≤1018。
题解
由于操作只有区间加,某处被一种土覆盖后就不会再改变,所以转化一下就是要求某处最早在第几次操作之后被覆盖。
最直接的做法是按时间建主席树然后二分 O ( n log 2 n ) O(n\log^2n) O(nlog2n),但是这题只能过 80 分。这时就有人钻研出一个 log \log log 的整体二分做法,但是没必要。
再次转化,把询问离线下来,按 x x x 从小到大排序,那么每次操作相当于对一段区间的询问的 y y y 值做区间减。如果某个值被减得 ≤ 0 \le0 ≤0 了,那么就可以把这个询问处理掉了。
这样复杂度优化到了 O ( n log n ) O(n\log n) O(nlogn),配合zkw线段树就完全不用担心常数问题。
代码
#include<cstdio>//JZM yyds!!
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define ll long long
#define uns unsigned
#define MOD
#define MAXN 1000005
#define INF 1e17
#define IF (it->first)
#define IS (it->second)
using namespace std;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0)f^=(s=='-'),s=getchar();
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
return f?x:-x;
}
int pt[30],lp;
inline void print(ll x,char c='\n'){
if(x<0)putchar('-'),x=-x;
pt[lp=1]=x%10;
while(x>9)x/=10,pt[++lp]=x%10;
while(lp)putchar(pt[lp--]^48);
putchar(c);
}
inline ll lowbit(ll x){return x&-x;}
int n,Q,m,p;
struct itn{
int x,y;ll z;itn(){}
itn(int X,int Y,ll Z){x=X,y=Y,z=Z;}
}a[MAXN],cz[MAXN];
int b[MAXN],ti[MAXN];
//zkw---
ll f[MAXN*3],lz[MAXN*3];
inline void change(int x,ll d){
for(f[p+x]=d,x=(p+x)>>1;x;x>>=1)
f[x]=min(f[x<<1],f[x<<1|1])-lz[x];
}
inline void add(int l,int r,ll d){
for(l=p+l-1,r=p+r+1;l^1^r;){
if(~l&1)f[l^1]-=d,lz[l^1]+=d;
if(r&1)f[r^1]-=d,lz[r^1]+=d;
l>>=1,r>>=1;
f[l]=min(f[l<<1],f[l<<1|1])-lz[l];
f[r]=min(f[r<<1],f[r<<1|1])-lz[r];
}
for(l>>=1;l;l>>=1)
f[l]=min(f[l<<1],f[l<<1|1])-lz[l];
}
int del[MAXN],le,ans[MAXN];
queue<itn>q;
inline void sch(){
le=0;
while(!q.empty())q.pop();
q.push(itn(1,0,0));
while(!q.empty()){
itn x=q.front();q.pop();
if(f[x.x]-x.z>0)continue;
if(x.x>=p){del[++le]=x.x-p;continue;}
x.z+=lz[x.x];
if(f[x.x<<1]-x.z<=0)q.push(itn(x.x<<1,0,x.z));
if(f[x.x<<1|1]-x.z<=0)q.push(itn(x.x<<1|1,0,x.z));
}
}
//------
signed main()
{
freopen("concrete.in","r",stdin);
freopen("concrete.out","w",stdout);
n=read(),Q=read();
memset(f,0x7f,sizeof(f));
for(int i=1;i<=Q;i++){
int op=read();
if(op==1){
int l=read(),r=read();
ll h=read();
cz[i]=itn(l,r,h);
}else{
int x=read();ll y=read();
m++,a[m]=itn(x,m,y),ti[m]=i;
}
}
sort(a+1,a+1+m,[](itn a,itn b){
return a.x<b.x;
});
for(int i=1;i<=m;i++)b[i]=a[i].x;
for(p=1;p<m+2;p<<=1);
for(int i=1;i<=m;i++)change(i,a[i].z);
for(int i=1;i<=Q;i++)if(cz[i].x){
int l=lower_bound(b+1,b+1+m,cz[i].x)-b;
int r=lower_bound(b+1,b+1+m,cz[i].y+1)-b-1;
add(l,r,cz[i].z),sch();
while(le--){
int x=del[le+1];
ans[a[x].y]=i,change(x,f[0]);
}
}
for(int i=1;i<=m;i++){
if(ans[i]>ti[i])ans[i]=0;
print(ans[i]);
}
return 0;
}