和Leo一起做爱线段树的好孩子COCI2017-2018被单

版权声明:LeoJAM Presents https://blog.csdn.net/fcb_x/article/details/82668720

一天,Little Donald想要洗干净他的n张被单。洗完所有被单之后,他把它们放在后院的平地上晒干。Donald很好的摆放了这些被单,使得这些被单两两之间不会在端点或边上接触,并且两两之间的边不会相交,但是可能一张更小的被单会放在一张更大的被单上面,或者一张被单会完全覆盖另外一张被单。做完这些事之后,Donald就去睡觉了。然而,Donald的朋友,Kim,知道了Donald正在晒被单并且决定恶搞Donald。他从他爸爸的阁楼找到了一把彩弹枪。在这把枪中有m颗彩弹,可能会有许多种不同颜色的彩弹,同时也可能有许多彩弹是有同一种颜色的。在Donald睡着之后,Kim就进到Donald家的后院并开始用彩弹枪向这些被单射击。每次一张被单被射击之后,这个彩弹的颜色就会染在这张被单以及所有在这张被单下面的被单上(注:在下面但不包含射击位置的被单不会被染色)。在Kim用完所有的彩弹之后,他就会开心地离开Donald家的后院。 
当Donald醒来并且到后院看到自己的被单的时候,他被震惊了。在Donald的大多数被单上面都有许多新的颜色。由于Donald对于正确的数据十分感兴趣,并且他被震惊到无法思考了,所以他想让你告诉他每张被单上面的颜色的数量。 
Donald的后院可以用一个平面坐标系表示,被单的边都是平行于坐标轴的,Kim射击的位置可以看成在平面中的一个点。 
注意:Kim的一次射击可能不会到任意一个被单上,射击的位置两两之间互不相同

线段树好题。

授信观察性质:题目是矩形嵌套的这是一个树形结构可以用扫描线+线段树永久化标记

为什么可以永久化标记:他们是包含关系。所以对y离散化

然后需要维护集合:

set肯定好用但是我得自己学习是吧

键值式线段树维护(永无乡等于没搞懂)

从小到大merge,做一个树形DP

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef int INT;
#define int long long
#define lc (p<<1)
#define rc (p<<1|1)
const int N=5e5+100;
inline void read(int &x){
	x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
struct Front_star{
	int u,v,nxt;
}e[N];
int cnt=0;
int first[N]={};
void add(int u,int v){
//	cout<<u<<" "<<v<<'\n';
	cnt++;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].nxt=first[u];
	first[u]=cnt;
}
//
int fa[N];
//
struct Node{
	int x,y,k,Id;
}A[N];
bool operator < (Node A,Node B){
	return A.x<B.x||(A.x==B.x&&A.Id>B.Id);
}
int acnt=0;
void Insert(int x,int y,int k,int Id){
	acnt++;
	A[acnt].x=x;
	A[acnt].y=y;
	A[acnt].k=k;
	A[acnt].Id=Id;
}
//
struct Segment_Tree{
	struct Node{
		int lson,rson,sum;
	}T[N<<2];	
	void PushDown(int p){
		if(T[p].sum<0)return;
		T[lc].sum=T[rc].sum=T[p].sum;
		T[p].sum=-1;
	}
	void Build(int p,int l,int r){
		T[p].sum=-1;
		T[p].lson=l;
		T[p].rson=r;
		if(l==r)return;
		int mid=(l+r)>>1;
		Build(lc,l,mid);
		Build(rc,mid+1,r);
	}
	void Update(int p,int l,int r,int val){
		if(l<=T[p].lson&&T[p].rson<=r){
			T[p].sum=val;
			return;
		}
		PushDown(p);
		int mid=(T[p].lson+T[p].rson)>>1;
		if(l<=mid)Update(lc,l,r,val);
		if(mid< r)Update(rc,l,r,val);
	}
	int Query(int p,int pos){
		if(T[p].sum>=0|T[p].lson==T[p].rson)return T[p].sum;
		if(!p)return 0;
		int mid=(T[p].lson+T[p].rson)>>1;
		if(pos<=mid)return Query(lc,pos);
		else return Query(rc,pos);
	}
}ST;
//
int root[N];
struct Chairman_Tree{
	int lson[N*20];
	int rson[N*20];	
	int sum[N*20];
	int cnt;
	void PushUp(int p){
		sum[p]=sum[lson[p]]+sum[rson[p]];
	}
	void Update(int &p,int l,int r,int pos){
		if(!p)p=++cnt;
		if(l==r){
			sum[p]=1;
			return;
		}
		int mid=(l+r)>>1;
		if(pos<=mid)Update(lson[p],l,mid,pos);
		else Update(rson[p],mid+1,r,pos);
		PushUp(p);
	}
	int Merge(int A,int B,int l,int r){
		if(!A|!B)return A^B;
		if(l==r)return A;
		int mid=(l+r)>>1;
		lson[A]=Merge(lson[A],lson[B],l,mid);
		rson[A]=Merge(rson[A],rson[B],mid+1,r);
		PushUp(A);
		return A;
	}
}CT;
//
int Y[N];
int sy;
int K[N];
int sk;
void Pre(){
	sort(Y+1,Y+1+sy);
	sort(K+1,K+1+sk);
	sort(A+1,A+1+acnt);
	sy=unique(Y+1,Y+1+sy)-Y-1;
	sk=unique(K+1,K+1+sk)-K-1;
}
//
int n,m;
int ans[N];
void DFS(int u){
//	cout<<u<<'\n';
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		DFS(v);
		root[u]=CT.Merge(root[u],root[v],1,sk);
	}
	ans[u]=CT.sum[root[u]];
}
INT main(){
//	freopen("test.in","r",stdin);
//	freopen("test.out","w",stdout);
	int size=40<<20;//40M	
	__asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));
	read(n);
	read(m);
	for(int i=1;i<=n;++i){
		int x1,y1,x2,y2;
		read(x1);read(y1);
		read(x2);read(y2);
		Insert(x1,y1,y2,i);
		Insert(x2,y1,y2,-i);
		Y[++sy]=y1;
		Y[++sy]=y2;
	}
	for(int i=1;i<=m;++i){
		int x,y,k;
		read(x);
		read(y);
		read(k);
		Insert(x,y,k,0);
		Y[++sy]=y;
		K[++sk]=k;
	}
	Pre();
	ST.Build(1,1,sy);
	for(int i=1;i<=acnt;++i){
		A[i].y=lower_bound(Y+1,Y+1+sy,A[i].y)-Y;
		if(A[i].Id){
			if(A[i].Id>0){
				if((fa[A[i].Id]=ST.Query(1,A[i].y))>0)add(fa[A[i].Id],A[i].Id);
				A[i].k=lower_bound(Y+1,Y+1+sy,A[i].k)-Y;
				ST.Update(1,A[i].y,A[i].k,A[i].Id);
			}
			else{
				A[i].k=lower_bound(Y+1,Y+1+sy,A[i].k)-Y;
				ST.Update(1,A[i].y,A[i].k,max(fa[-A[i].Id],(int)0));
			}
		}
		else{
			A[i].k=lower_bound(K+1,K+1+sk,A[i].k)-K;
			int pos=ST.Query(1,A[i].y);
//			cout<<pos<<'\n';
			if(pos>0)CT.Update(root[pos],1,sk,A[i].k);
//			cout<<pos<<" "<<A[i].k<<'\n';
		}
	}
	for(int i=1;i<=n;++i){
		if(fa[i]<=0)DFS(i);
	}
	for(int i=1;i<=n;++i){
		cout<<ans[i]<<'\n';
	}
	exit(0);
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/82668720