第15回日本情報オリンピック 本選 E - 断層 (Geologic Fault) 题解

题目链接:E - 断層 (Geologic Fault)

题目大意:给定一个平面直角坐标系, x 轴以下每一个 y 为整数的位置都有一条直线,这些直线从上到下依次编号 \(0\sim \infty\) ,接下来有 \(q\) 个操作,每一个操作代表将一条经过 \((x_i,0)\) 的斜率为 \(\pm 1\) 的斜线上方的射线全部沿斜线向上平移一格(每一个点上的标号也随之平移),最后询问 \(y=0\) 这一条直线上的前 \(n\) 个点的标号。


题解:正难则反,我们将询问离线倒过来考虑,结果就是第一层的每一个节点最后到达了哪一层。

由于斜着非常令人讨厌,所以我们将这个坐标轴旋转 \(45 ^{\circ}\) 变成每一次将 \(x\) 坐标小于等于 \(x_i\) 节点的 \(y\) 坐标减去 \(2 \cdot l_i\) 或将 \(y\) 坐标大于 \(x_i\) 的点的 \(x\) 坐标加上 \(2\cdot l_i\) ,最后每一个点的答案就是 \(\frac{x_y-y_i}{2}\)

容易发现 \(x,y\) 坐标均具有单调性,直接线段树解决即可。

时间复杂度 \(O(n\log n)\)

代码:

#include <cstdio>
template<typename Elem>
Elem min(Elem a,Elem b){
	return a<b?a:b;
}
template<typename Elem>
Elem max(Elem a,Elem b){
	return a>b?a:b;
}
typedef long long ll;
const int Maxn=200000;
int n,q;
struct Question{
	int x,d,l;
}qu[Maxn+5];
struct Segment_Node{
	ll maxn_x,minn_x;
	ll maxn_y,minn_y;
	ll lazy_x,lazy_y;
}seg[Maxn<<2|5];
void update_tag_x(int root,ll x){
	seg[root].maxn_x+=x;
	seg[root].minn_x+=x;
	seg[root].lazy_x+=x;
}
void update_tag_y(int root,ll y){
	seg[root].maxn_y+=y;
	seg[root].minn_y+=y;
	seg[root].lazy_y+=y;
}
void push_down(int root){
	if(seg[root].lazy_x){
		update_tag_x(root<<1,seg[root].lazy_x);
		update_tag_x(root<<1|1,seg[root].lazy_x);
		seg[root].lazy_x=0;
	}
	if(seg[root].lazy_y){
		update_tag_y(root<<1,seg[root].lazy_y);
		update_tag_y(root<<1|1,seg[root].lazy_y);
		seg[root].lazy_y=0;
	}
}
void push_up(int root){
	seg[root].maxn_x=max(seg[root<<1].maxn_x,seg[root<<1|1].maxn_x);
	seg[root].minn_x=min(seg[root<<1].minn_x,seg[root<<1|1].minn_x);
	seg[root].maxn_y=max(seg[root<<1].maxn_y,seg[root<<1|1].maxn_y);
	seg[root].minn_y=min(seg[root<<1].minn_y,seg[root<<1|1].minn_y);
}
void build(int root=1,int left=1,int right=n){
	seg[root].lazy_x=seg[root].lazy_y=0;
	if(left==right){
		seg[root].maxn_x=seg[root].minn_x=seg[root].maxn_y=seg[root].minn_y=left;
		return;
	}
	int mid=(left+right)>>1;
	build(root<<1,left,mid);
	build(root<<1|1,mid+1,right);
	push_up(root);
}
void update_x(int x,int y,int root=1,int left=1,int right=n){
	if(seg[root].maxn_x<=x){
		update_tag_y(root,y);
		return;
	}
	if(seg[root].minn_x>x){
		return;
	}
	push_down(root);
	int mid=(left+right)>>1;
	update_x(x,y,root<<1,left,mid);
	update_x(x,y,root<<1|1,mid+1,right);
	push_up(root);
}
void update_y(int x,int y,int root=1,int left=1,int right=n){
	if(seg[root].minn_y>y){
		update_tag_x(root,x);
		return;
	}
	if(seg[root].maxn_y<=y){
		return;
	}
	push_down(root);
	int mid=(left+right)>>1;
	update_y(x,y,root<<1,left,mid);
	update_y(x,y,root<<1|1,mid+1,right);
	push_up(root);
}
struct Node{
	ll x,y;
}ans[Maxn+5];
void query(int root=1,int left=1,int right=n){
	if(left==right){
		ans[left].x=seg[root].minn_x;
		ans[left].y=seg[root].minn_y;
		return;
	}
	push_down(root);
	int mid=(left+right)>>1;
	query(root<<1,left,mid);
	query(root<<1|1,mid+1,right);
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=q;i++){
		scanf("%d%d%d",&qu[i].x,&qu[i].d,&qu[i].l);
	}
	build();
	for(int i=q;i>0;i--){
		if(qu[i].d==1){
			update_x(qu[i].x,-2*qu[i].l);
		}
		else{
			update_y(2*qu[i].l,qu[i].x);
		}
	}
	query();
	for(int i=1;i<=n;i++){
		printf("%lld\n",(ans[i].x-ans[i].y)/2);
	}
	return 0;
}

posted @ 2020-11-11 21:08  with_hope  阅读(78)  评论(0编辑  收藏  举报