WC2012 记忆中的水杉树

有诗意的名字,但这码量也太大了吧。

第一个想法就是我们可以对上下、左右建立两个DAG。从i连向j表示在删掉j前,你要把i删掉才行。

直接建图是O(n2)的,肯定过不了。

这里我们就要使用扫描线:比如对于上下方向,我们用一条x=i的垂直直线,从左往右扫。当我们加入一个线段i时,找到第一个大于它的线段x和第一个小于它的线段y,从y连向i,从i连向x

这样图的边数降为2n

但是有一个问题:我们如何找到第一个大于它的线段和第一个小于它的线段?直接用set貌似不行,因为x坐标在变化。但是其实是可以的,因为题中保证线段之间没有交点,所以尽管x在变化,但是每条线段的相对顺序不会交换,仍然满足平衡树的性质

此时第二问就很简单了,对上下方向的,按照拓扑序从小到大,并且每次操作都是向下平移即可。

对于第一问,我们可以从后往前做,找到四个方向对应的区间(l,r)(左开右开),查找对应的区间内部拓扑值是否有小于或大于它的,这样,我们只要再维护两个支持区间修改min&max区间查询min&max的线段树即可。

时间复杂度为O(nlogn)

写了230行,最后还附上一个针对第二问的HACK。

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

const int maxn=400005,inf=1000000000;
int n,mx,sz,a[maxn],b[maxn],c[maxn],d[maxn];
std::vector<int> nums,add[maxn],del[maxn];

int number(int num) {
	return std::lower_bound(nums.begin(),nums.end(),num)-nums.begin()+1;
}

int now;

struct line {
	double k,b;
	int id;
	bool operator == (const line &x) const {
		return id==x.id;
	}
	bool operator < (const line &x) const {
		return 1.0*now*k+b<1.0*now*x.k+x.b;
	}
}tmp[maxn];

std::vector<int> G[2][maxn];

void doit(int id) { 
	std::set<line> S;
	for(int i=1;i<=mx;i++) {
		now=nums[i-1];//注意这里不能是离散化后的,也就是不能写出now=i,详见HACK1 
		for(auto item : del[i]) {
			S.erase(tmp[item]); 
		}
		for(auto item : add[i]) {
			std::set<line>::iterator it=S.lower_bound(tmp[item]);
			if(it!=S.begin()) {
				it--;
				G[id][it->id].push_back(item);
				it++;
			}
			if(it!=S.end()) {
				G[id][item].push_back(it->id);
			}
			S.insert(tmp[item]);
		}
		add[i].clear(); del[i].clear();
	}
}

int in[maxn],per[2][maxn];

void toposort(int id) {
	memset(in,0,sizeof in);
	for(int i=1;i<=n;i++) {
		for(auto nxt : G[id][i]) {
			in[nxt]++;
		}
	}
	std::queue<int> q;
	int cur=0;
	for(int i=1;i<=n;i++) {
		if(!in[i]) q.push(i);
	}
	while(!q.empty()) {
		int pos=q.front(); q.pop();
		per[id][pos]=++cur;
		for(auto nxt : G[id][pos]) {
			in[nxt]--;
			if(!in[nxt]) q.push(nxt);
		}
	}
}

int p[maxn],q[maxn],seq[maxn];

struct sgt {
	int mn[maxn+maxn<<2],mx[maxn+maxn<<2],lzy_mn[maxn+maxn<<2],lzy_mx[maxn+maxn<<2];
	void build(int pos=1,int lef=1,int rig=sz) {
		mn[pos]=lzy_mn[pos]=inf,mx[pos]=lzy_mx[pos]=-inf;
		if(lef==rig) return;
		int mid=lef+rig>>1;
		build(pos<<1,lef,mid);
		build(pos<<1|1,mid+1,rig);
	}
	void GetNewMin(int pos,int num) {
		mn[pos]=std::min(mn[pos],num);
		if(num!=inf) mx[pos]=std::max(mx[pos],num); 
		lzy_mn[pos]=std::min(lzy_mn[pos],num);
	}
	void GetNewMax(int pos,int num) {
		if(num!=-inf) mn[pos]=std::min(mn[pos],num);
		mx[pos]=std::max(mx[pos],num);
		lzy_mx[pos]=std::max(lzy_mx[pos],num);
	}
	void pushdown(int pos) {
		GetNewMin(pos<<1,lzy_mn[pos]);
		GetNewMin(pos<<1|1,lzy_mn[pos]);
		GetNewMax(pos<<1,lzy_mx[pos]);
		GetNewMax(pos<<1|1,lzy_mx[pos]);
		lzy_mn[pos]=inf,lzy_mx[pos]=-inf;
	}
	void pushup(int pos) {
		mn[pos]=std::min(mn[pos<<1],mn[pos<<1|1]);
		mx[pos]=std::max(mx[pos<<1],mx[pos<<1|1]);
	}
	void update_mn(int l,int r,int num,int pos=1,int lef=1,int rig=sz) {
		if(l<=lef&&rig<=r) {
			GetNewMin(pos,num);
		} else if(l<=rig&&lef<=r) {
			pushdown(pos);
			int mid=lef+rig>>1;
			update_mn(l,r,num,pos<<1,lef,mid); update_mn(l,r,num,pos<<1|1,mid+1,rig);
			pushup(pos);
		}
	}
	void update_mx(int l,int r,int num,int pos=1,int lef=1,int rig=sz) {
		if(l<=lef&&rig<=r) {
			GetNewMax(pos,num);
		} else if(l<=rig&&lef<=r) {
			pushdown(pos);
			int mid=lef+rig>>1;
			update_mx(l,r,num,pos<<1,lef,mid); update_mx(l,r,num,pos<<1|1,mid+1,rig);
			pushup(pos);
		}
	}
	int query_mn(int l,int r,int pos=1,int lef=1,int rig=sz) {
		if(l<=lef&&rig<=r) {
			return mn[pos];
		} else if(l<=rig&&lef<=r) {
			pushdown(pos);
			int mid=lef+rig>>1;
			int ret=std::min(query_mn(l,r,pos<<1,lef,mid),query_mn(l,r,pos<<1|1,mid+1,rig));
			pushup(pos); 
			return ret;
		}
		return inf;
	}
	int query_mx(int l,int r,int pos=1,int lef=1,int rig=sz) {
		if(l<=lef&&rig<=r) {
			return mx[pos];
		} else if(l<=rig&&lef<=r) {
			pushdown(pos);
			int mid=lef+rig>>1;
			int ret=std::max(query_mx(l,r,pos<<1,lef,mid),query_mx(l,r,pos<<1|1,mid+1,rig));
			pushup(pos);
			return ret;
		}
		return -inf;
	}
}lr,ud;

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
		nums.insert(nums.end(),{a[i],b[i],c[i],d[i]});
	}
	std::sort(nums.begin(),nums.end());
	nums.erase(std::unique(nums.begin(),nums.end()),nums.end());
	mx=nums.size();
	
	for(int i=1;i<=n;i++) {
		int from=number(a[i]),to=number(c[i]);
		if(from>to) std::swap(from,to);
		add[from].push_back(i);
		del[to].push_back(i);
		tmp[i].k=(double)(b[i]-d[i])/(double)(a[i]-c[i]);
		tmp[i].b=(double)b[i]-(double)a[i]*tmp[i].k;
		tmp[i].id=i;
	}
	doit(0);
	for(int i=1;i<=n;i++) {
		int from=number(b[i]),to=number(d[i]);
		if(from>to) std::swap(from,to);
		add[from].push_back(i);
		del[to].push_back(i);
		tmp[i].k=(double)(a[i]-c[i])/(double)(b[i]-d[i]);
		tmp[i].b=(double)a[i]-(double)b[i]*tmp[i].k;
		tmp[i].id=i;
	}
	doit(1);
	toposort(0);
	toposort(1);
	
	for(int i=1;i<=n;i++) {
		scanf("%d%d",&p[i],&q[i]);
	}
	
	sz=mx+mx;
	lr.build();
	ud.build();
	
	int ans;
	for(int i=n;i>=1;i--) {
		{
			//l and r
			int from=number(b[p[i]])*2,to=number(d[p[i]])*2;
			if(from>to) std::swap(from,to); to--;
			if(q[i]==0&&lr.query_mn(from,to)<per[1][p[i]]) {
				ans=i;
			}
			if(q[i]==2&&lr.query_mx(from,to)>per[1][p[i]]) {
				ans=i;
			}
			lr.update_mn(from,to,per[1][p[i]]);
			lr.update_mx(from,to,per[1][p[i]]);
		}
		{
			//u and d
			int from=number(a[p[i]])*2,to=number(c[p[i]])*2;
			if(from>to) std::swap(from,to); to--;
			if(q[i]==3&&ud.query_mn(from,to)<per[0][p[i]]) {
				ans=i;
			}
			if(q[i]==1&&ud.query_mx(from,to)>per[0][p[i]]) {
				ans=i;
			}
			ud.update_mn(from,to,per[0][p[i]]);
			ud.update_mx(from,to,per[0][p[i]]);
		}
	}
	
	printf("%d\n",ans);
	
	for(int i=1;i<=n;i++) seq[per[0][i]]=i;
	for(int i=1;i<=n;i++) {
		printf("%d 3\n",seq[i]);
	}

	return 0;
}

/*
Hack1
8
0 1 2 2
3 3 1 0
2 0 4 2
5 3 2 4
4 3 6 1 
4 4 7 5
6 2 7 3
7 1 6 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
*/ 
posted @   Nastia  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示