首先发现斜着平移比较难处理,所以考虑将平面逆时针旋转 \(45°\)。
接着发现风化也不好处理,但是风化的一定不会作为答案,所以我们可以离线,然后倒着处理操作,上升变为下降。
我们发现每个初始 \(0\) 点最后的坐标就是它正着做时初始的坐标,且每次操作都只会将连续一段点的 \(x,y\) 坐标修改。
我们可以开两棵线段树,一棵维护 \(x\) 坐标,一棵维护 \(y\) 坐标。
容易发现,操作规律:
对于操作一,将维护 \(y\) 坐标的线段树中所有 \(x\) 坐标小于 \(x_i\) 的 \(y\) 坐标减去 \(2 \cdot d_i\)。
对于操作二,将维护 \(x\) 坐标的线段树中所有 \(y\) 坐标大于 \(x_i\) 的 \(x\) 坐标增加 \(2 \cdot d_i\)。
至于为什么乘二,是因为旋转后中间有空隙。
但是我们发现这个修改位置无法直接确定,于是我们可以在线段树上二分修改的位置。当修改 \(y\) 坐标时,我们在 \(x\) 线段树上二分小于 \(x_i\) 的最大的 \(x\),当修改 \(x\) 坐标时,在 \(y\) 线段树上二分大于 \(x_i\) 的最小的 \(y\)。
至于为什么能二分:
显然相邻的两个 \(0\) 的 相对位置是不变的,所以小于一个值的坐标一定在一个区间内。
二分到位置后修改,注意到有可能搜不到这个点,此时不修改就行了。
code:
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define debug cout<<"debug\n"
#define vi vector<int>
#define imp map<int,int>
#define il inline
#define pb push_back
using namespace std;
const int N=2e5+5,inf=0x7fffffff;
int n,q;
ll seg[3][N],a[N][5],lt[3][N],ans[3][N];
int ls(int x){
return x<<1;
}
int rs(int x){
return x<<1|1;
}
void build(int l,int r,int p){
if(l==r){
seg[0][p]=seg[1][p]=l;
return;
}
int mid=(l+r)>>1;
build(l,mid,ls(p));
build(mid+1,r,rs(p));
seg[0][p]=min(seg[0][ls(p)],seg[0][rs(p)]);
seg[1][p]=min(seg[1][ls(p)],seg[1][rs(p)]);
}
void pushdown(int op,int l,int r,int p){
seg[op][ls(p)]+=lt[op][p];
seg[op][rs(p)]+=lt[op][p];
lt[op][ls(p)]+=lt[op][p];
lt[op][rs(p)]+=lt[op][p];
lt[op][p]=0;
}
void getans(int l,int r,int p){
if(l==r){
ans[0][l]=seg[0][p];
ans[1][l]=seg[1][p];
return;
}
pushdown(0,l,r,p);
pushdown(1,l,r,p);
int mid=(l+r)>>1;
getans(l,mid,ls(p));
getans(mid+1,r,rs(p));
}
void findx(int nx,int ny,int l,int p,int &ans){
if(nx==ny){
if(seg[0][p]<=l){
ans=nx;
}
return;
}
pushdown(0,nx,ny,p);
int mid=(nx+ny)>>1;
if(l>=seg[0][rs(p)]){
findx(mid+1,ny,l,rs(p),ans);
}else{
findx(nx,mid,l,ls(p),ans);
}
}
void findy(int nx,int ny,int l,int p,int &ans){
if(nx==ny){
if(seg[1][p]>l){
ans=nx;
}
return;
}
pushdown(1,nx,ny,p);
int mid=(nx+ny)>>1;
if(l<seg[1][rs(p)]){
ans=min(ans,mid+1);
findy(nx,mid,l,ls(p),ans);
}else{
findy(mid+1,ny,l,rs(p),ans);
}
}
void change(int op,int nx,int ny,int l,int r,int p,ll d){
if(l<=nx&&ny<=r){
seg[op][p]+=d;
lt[op][p]+=d;
return;
}
pushdown(op,nx,ny,p);
int mid=(nx+ny)>>1;
if(l<=mid){
change(op,nx,mid,l,r,ls(p),d);
}
if(mid<r){
change(op,mid+1,ny,l,r,rs(p),d);
}
seg[op][p]=min(seg[op][ls(p)],seg[op][rs(p)]);
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=q;i++){
cin>>a[i][0]>>a[i][1]>>a[i][2];
}
build(1,n,1);
for(int i=q;i>=1;i--){
int x=a[i][0],y=a[i][1],z=a[i][2];
if(y==1){
int res=-inf;
findx(1,n,x,1,res);
if(res!=-inf){
change(1,1,n,1,res,1,-2*z);
}
}else{
int res=inf;
findy(1,n,x,1,res);
if(res!=inf){
change(0,1,n,res,n,1,2*z);
}
}
}
getans(1,n,1);
for(int i=1;i<=n;i++){
cout<<(ans[0][i]-ans[1][i])/2<<"\n";
}
return 0;
}