1. 程式人生 > >【線段樹】「CodePlus 2018 3 月賽」白金元首與克勞德斯

【線段樹】「CodePlus 2018 3 月賽」白金元首與克勞德斯

題意:

在這裡插入圖片描述

分析:

題意好鬼扯。。。

非常傻逼的線段樹動態開點題。

橫向移動的矩形和縱向移動的矩形,看起來非常麻煩。

由於速度均相等,所以可以以所有縱向移動的矩形為參考系,那麼所有縱向移動的矩形都是相對靜止的。而此時橫向移動的矩形就變成了沿主對角線移動(左上至右下),那麼就可以旋轉座標系,變成簡單的線段覆蓋問題了。

即:把每個縱向移動的矩形視為 ( x +

y , x + w + y + h )
(x+y,x+w+y+h)
的線段,然後橫向移動的視為 ( x + y
, x + w + y + h ) (x'+y',x'+w'+y'+h')
的詢問,只要任意一個詢問的區間中,有某個點被線段覆蓋了,那麼答案就是2,否則答案就是1。

順便提供一下用於評測本題的網站

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 100010
#define INF 2000000000
using namespace std;
struct node{
	int pl,pr;
	bool flag;	
}tree[MAXN*40];
pair<int,int> line[MAXN];
int rt=1,ncnt=1;
void add_line(int id,int l,int r,int l1,int r1){
	if(l>=l1&&r<=r1){
		tree[id].flag=1;
		return ;
	}
	int mid=1ll*(l+r)>>1ll;
	if(l1<=mid){
		if(tree[id].pl==0){
			tree[id].pl=++ncnt;
			tree[ncnt].pl=tree[ncnt].pr=0;
		}
		add_line(tree[id].pl,l,mid,l1,r1);
	}
	if(r1>mid){
		if(tree[id].pr==0){
			tree[id].pr=++ncnt;
			tree[ncnt].pl=tree[ncnt].pr=0;
		}
		add_line(tree[id].pr,mid+1,r,l1,r1);	
	}
	tree[id].flag=(tree[tree[id].pl].flag)&(tree[tree[id].pr].flag);
}
bool query(int l1,int r1,int id=1,int l=-INF,int r=INF){
	if(tree[id].flag==1)
		return 1;
	if(l>=l1&&r<=r1)
		return 1;
	int mid=1ll*(l+r)>>1ll;
	if(l1<=mid&&tree[id].pl!=0){
		if(query(l1,r1,tree[id].pl,l,mid))
			return 1;
	}
	if(r1>mid&&tree[id].pr!=0){
		if(query(l1,r1,tree[id].pr,mid+1,r))
			return 1;
	}
	return 0;
}
int main(){
	int t,n,cnt;
	SF("%d",&t);
	while(t--){
		SF("%d",&n);
		cnt=0;
		ncnt=1;
		tree[rt].pl=tree[rt].pr=0;
		int x,y,w,h,d;
		for(int i=1;i<=n;i++){
			SF("%d%d%d%d%d",&x,&y,&w,&h,&d);
			if(d==0)
				line[++cnt]=make_pair(x+y,x+y+w+h);	
			else
				add_line(rt,-INF,INF,x+y,x+y+w+h);
		}
		int ans=1;
		for(int i=1;i<=cnt;i++)
			if(query(line[i].first+1,line[i].second-1)){
				ans=2;
				break;
			}
		PF("%d\n",ans);
	}
}