【BZOJ】【P2584】【Wc2012】【memory】【题解】【线段树+扫描线+拓扑排序】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2584

首先考虑第二问

显然只向一个方向移动一定有解 假设向上

显然构成了一个DAG图,拓扑排序即可

那么如何构造DAG图

由于线段是不相交的,所以在相邻两个横坐标之间的线段在y方向的相对位置不变!!!!

扫描线+set 维护前趋后继构建DAG图

考虑第一问

分别考虑水平和竖直方向

假设我们求出了竖直方向的拓扑序

把移除一个线段倒序改为添加一个线段

那么从上往下添加线段=>离散后的横坐标区间中的拓扑标号大于它

从下往上添加线段=>离散后的横坐标区间中的拓扑标号小于它

两个方向分别离散化+线段树,取其最小值即可

P.S.找来kAc的标程想对拍,然后越改越像越改越像……

Code:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
#include<cstring>
#define fst first
#define sec second
using namespace std;
typedef pair<int,int> par;
const int maxn=1e5+5;
const double eps=1e-6;
int dcmp(double x){return (x>eps)-(x<-eps);}
struct point{
	int x,y;
	bool operator==(point o)const{return x==o.x&&y==o.y;}
	bool operator<(const point &o)const{return x==o.x?y<o.y:x<o.x;}
};
int nowx;
struct line{
	point a,b;int id;
	double get(int x)const{return a.y+(double)(b.y-a.y)/(double)(b.x-a.x)*double(x-a.x);}
	bool operator<(const line &o)const{return get(nowx)-o.get(nowx)<-eps;}
}lin[maxn];
set<line>S;
int n,in[maxn],anss[maxn],size;
par Q[maxn];
int X[maxn<<1];
int uniqX(int x){return lower_bound(X+1,X+1+X[0],x)-X;}
vector<int>G[maxn];
void add(int u,int v){
	G[u].push_back(v);
}
void topsort(){
	queue<int>q;
	for(int i=1;i<=n;i++)if(!in[i]){q.push(i);anss[++anss[0]]=i;}
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=0,v;i<G[u].size();i++)
		if(!--in[v=G[u][i]])q.push(v),anss[++anss[0]]=v;
	}
}
const int inf=1e9+10;
struct Tsgt{
	int mn[maxn<<3],mx[maxn<<3],_mn[maxn<<3],_mx[maxn<<3];
	void clear(){ 
		memset(mn, 0x3f, sizeof(mn));memset(mx, 0xe0, sizeof(mx)); 
		memset(_mn, 0x3f, sizeof(_mn));memset(_mx, 0xe0, sizeof(_mx));
	}
	void minadd(int i, int d){
		mn[i] = min(mn[i], d); 
		_mn[i] = min(_mn[i], d); 
	}
	void maxadd(int i, int d){
		mx[i] = max(mx[i], d);
		_mx[i] = max(_mx[i], d);
	}
	void update(int i){
		mx[i] = max(mx[i * 2], mx[i * 2 + 1]);
		mn[i] = min(mn[i * 2], mn[i * 2 + 1]);
	}
	void pd(int i){
		if (_mn[i] != 0x3f3f3f3f) { minadd(i * 2, _mn[i]); minadd(i * 2 + 1, _mn[i]); }
		if (_mx[i] != 0xe0e0e0e0) { maxadd(i * 2, _mx[i]); maxadd(i * 2 + 1, _mx[i]); }
		_mn[i] = 0x3f3f3f3f; _mx[i] = 0xe0e0e0e0;
	}
	void Change(int i, int l, int r, int l0, int r0, int d){
		if (l0 <= l && r0 >= r) { minadd(i, d); maxadd(i, d); return; }
		int m = l + r >> 1;
		pd(i);
		if (l0 < m) Change(i * 2, l, m, l0, r0, d);
		if (r0 > m) Change(i * 2 + 1, m, r, l0, r0, d);
		update(i);
	}
	int Qmin(int i, int l, int r, int l0, int r0){
		if (l0 <= l && r0 >= r) return mn[i];
		int m = l + r >> 1;
		pd(i);
		int ans = 0x3f3f3f3f;
		if (l0 < m) ans = min(ans, Qmin(i * 2, l, m, l0, r0));
		if (r0 > m) ans = min(ans, Qmin(i * 2 + 1, m, r, l0, r0));
		update(i);
		return ans;
	}
	int Qmax(int i, int l, int r, int l0, int r0){
		if (l0 <= l && r0 >= r) return mx[i];
		int m = l + r >> 1;
		pd(i);
		int ans = 0xe0e0e0e0;
		if (l0 < m) ans = max(ans, Qmax(i * 2, l, m, l0, r0));
		if (r0 > m) ans = max(ans, Qmax(i * 2 + 1, m, r, l0, r0));
		update(i);
		return ans;
	}
}T;
int getint(){int x;scanf("%d",&x);return x;}
struct scanline{
	int op,id,x;
	bool operator<(const scanline &o)const{return x!=o.x?x<o.x:op<o.op;}
}scan[maxn<<2];
int val[maxn];
int solve(int d){
	S.clear();size=0;T.clear();
	for(int i=1;i<=n;i++){
		G[i].clear();
		scan[++size]=(scanline){1,i,lin[i].a.x};
		scan[++size]=(scanline){2,i,lin[i].a.x};
		scan[++size]=(scanline){2,i,lin[i].b.x};
		scan[++size]=(scanline){3,i,lin[i].b.x};
	}sort(scan+1,scan+1+size);X[0]=0;
	for(int i=1;i<=n;i++)X[++X[0]]=lin[i].a.x,X[++X[0]]=lin[i].b.x;
	sort(X+1,X+1+X[0]);X[0]=unique(X+1,X+1+X[0])-X-1;
	for(int i=1;i<=size;i++){
		set<line>::iterator it,iter;
		nowx=scan[i].x;
		if(scan[i].op==1)S.insert(lin[scan[i].id]);	
		else if(scan[i].op==2){
			it=S.find(lin[scan[i].id]);iter=it;iter++;
			if(it!=S.begin()){it--;add(scan[i].id,it->id);in[it->id]++;}
			if(iter!=S.end()){add(iter->id,scan[i].id);in[scan[i].id]++;}
		}else S.erase(lin[scan[i].id]);
	}anss[0]=0;topsort();
	for(int i=1;i<=n;i++)val[anss[i]]=i;	
	int ans=n;
	for(int i=n;i>=1;i--){
		int id=Q[i].fst,di=Q[i].sec;	
		if((di&1)==d){
			if(di>>1)
				{if(T.Qmax(1,1,X[0],uniqX(lin[id].a.x),uniqX(lin[id].b.x))>val[id])ans=i;}
			else {if(T.Qmin(1,1,X[0],uniqX(lin[id].a.x),uniqX(lin[id].b.x))<val[id])ans=i;}			
		}T.Change(1,1,X[0],uniqX(lin[id].a.x),uniqX(lin[id].b.x),val[id]);
	}return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		point a,b;a.x=getint();a.y=getint();
		b.x=getint();b.y=getint();
		if(b<a)swap(a,b);
		lin[i]=(line){a,b,i};
	}for(int i=1;i<=n;i++)Q[i].fst=getint(),Q[i].sec=getint();
	int ans=solve(1);
	for (int i=1;i<=n;i++){
		swap(lin[i].a.x,lin[i].a.y);
		swap(lin[i].b.x,lin[i].b.y);
		lin[i].a.y*=-1;lin[i].b.y*=-1;
		if(lin[i].b<lin[i].a)swap(lin[i].a,lin[i].b);
	}ans=min(ans,solve(0));
	cout<<ans<<endl;
	for(int i=1;i<=n;i++)printf("%d 0\n",anss[i]);
	return 0;
}



你可能感兴趣的:(bzoj)