[扫描线 线段树 拓扑排序] BZOJ2584 [Wc2012]memory

%%% zky :http://blog.csdn.net/iamzky/article/details/42166795


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

自己YY出来一个区间取 max min 的线段树

找来zky的程序 然后越改越像


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#define V G[p].v
#define eps 1e-6
#define cl(x) memset(x,0,sizeof(x))
using namespace std;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int maxn=100005;

struct SEGTREE{
	int Mx[maxn*8],Mn[maxn*8],HMx[maxn*8],HMn[maxn*8];
	int M,TH;
	inline void Pushup(int p){
		Mx[p]=max(Mx[p<<1],Mx[p<<1|1]);
		Mn[p]=min(Mn[p<<1],Mn[p<<1|1]);
	}
	inline void Build(int n){
		for (M=1,TH=0;M<n+2;M<<=1,TH++);
		memset(Mx,0,sizeof(Mx));
		memset(Mn,0x7f,sizeof(Mn));
		memset(HMx,0,sizeof(HMx));
		memset(HMn,0x7f,sizeof(HMn));
	}
	inline void Pushdown(int rt){
		int p;
		for (int i=TH;i;i--)
		{
			if (HMx[p=rt>>i])
			{
				HMx[p<<1]=max(HMx[p<<1],HMx[p]);
				HMx[p<<1|1]=max(HMx[p<<1|1],HMx[p]);
				if (HMx[p]>Mx[p<<1])
					Mx[p<<1]=HMx[p];
				if (HMx[p]>Mx[p<<1|1])
					Mx[p<<1|1]=HMx[p];
				HMx[p]=0;
			}
			if (HMn[p]<0x7f7f7f7f)
			{
				HMn[p<<1]=min(HMn[p<<1],HMn[p]);
				HMn[p<<1|1]=min(HMn[p<<1|1],HMn[p]);
				if (HMn[p]<Mn[p<<1])
					Mn[p<<1]=HMn[p];
				if (HMn[p]<Mn[p<<1|1])
					Mn[p<<1|1]=HMn[p];
				HMn[p]=0x7f7f7f7f;
			}
		}
	}
	inline void Change(int s,int t,int r){
		for (Pushdown(s+=M-1),Pushdown(t+=M+1);s^t^1;Pushup(s>>=1),Pushup(t>>=1))
		{
			if (~s&1) 
			{
				HMn[s^1]=min(HMn[s^1],r);
				HMx[s^1]=max(HMx[s^1],r);
				if (r<Mn[s^1])
					Mn[s^1]=r;
				if (r>Mx[s^1])
					Mx[s^1]=r;
			}
			if ( t&1) 
			{
				HMn[t^1]=min(HMn[t^1],r);
				HMx[t^1]=max(HMx[t^1],r);
				if (r<Mn[t^1])
					Mn[t^1]=r;
				if (r>Mx[t^1])
					Mx[t^1]=r;
			}
		}
		while (s>>=1)
			Pushup(s);
	}
	inline int Max(int s,int t){
		int ret=0;
		for (Pushdown(s+=M-1),Pushdown(t+=M+1);s^t^1;s>>=1,t>>=1)
		{
			if (~s&1) ret=max(ret,Mx[s^1]);
			if ( t&1) ret=max(ret,Mx[t^1]);
		}
		return ret;
	}
	inline int Min(int s,int t){
		int ret=1<<30;
		for (Pushdown(s+=M-1),Pushdown(t+=M+1);s^t^1;s>>=1,t>>=1)
		{
			if (~s&1) ret=min(ret,Mn[s^1]);
			if ( t&1) ret=min(ret,Mn[t^1]);
		}
		return ret;
	}
}SEG;

struct edge{
	int u,v;
	int next;
};

edge G[1000005];
int head[maxn],inum;

inline void add(int u,int v,int p){
	G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

int n,Ans;
int lst[maxn],pnt,vst[maxn];
int rank[maxn];

inline void dfs(int u){
	vst[u]=1;
	for (int p=head[u];p;p=G[p].next)
		if (!vst[V])
			dfs(V);
	lst[++pnt]=u;
}

inline void Topo()
{
	cl(vst); pnt=0;
	for (int i=1;i<=n;i++)
		if (!vst[i])
			dfs(i);
	reverse(lst+1,lst+n+1);
}

inline int dcmp(double a,double b)
{
	if (fabs(a-b)<eps) return 0;
	if (a<b) return -1;
	return 1;
} 

struct Point{  
    int x,y;  
    Point(int x=0,int y=0):x(x),y(y) { }
    inline bool operator == (const Point &B) const{
		return x==B.x && y==B.y;
	}  
    inline bool operator < (const Point &B) const{
		return x==B.x?y<B.y:x<B.x;
	}  
}; 

int Curx;  
struct Line{  
    Point a,b;
	int id;  
	Line(Point a=Point(0,0),Point b=Point(0,0),int id=0):a(a),b(b),id(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 &B)const{
		return dcmp(get(Curx),B.get(Curx))<0;
	}  
}L[maxn];  

set<Line> Set;
typedef set<Line>::iterator ITER;

struct event{
	int x,id,f;
	event(int x=0,int id=0,int f=0):x(x),id(id),f(f) { }
	bool operator < (const event &B) const{
		return x==B.x?f<B.f:x<B.x;
	}
}eve[4*maxn];
int tot;

pair<int,int> Q[maxn];

int uniq[2*maxn];
int icnt;

inline int Bin(int x){
	return lower_bound(uniq+1,uniq+icnt+1,x)-uniq;
} 

inline int Solve(int d)
{
	tot=0;
	for (int i=1;i<=n;i++)
	{
		eve[++tot]=event(L[i].a.x,i,1);
		eve[++tot]=event(L[i].a.x,i,2);
		eve[++tot]=event(L[i].b.x,i,2);
		eve[++tot]=event(L[i].b.x,i,3);
	}
	sort(eve+1,eve+tot+1);
	Set.clear();
	for (int i=1;i<=tot;i++)
	{
		Curx=eve[i].x;
		if (eve[i].f==1)
		{
			Set.insert(L[eve[i].id]);
//			for (ITER j=Set.begin();j!=Set.end();j++) printf("%d ",j->id); printf("\n");
		}
		else if (eve[i].f==2)
		{
			ITER l,r;
			l=Set.find(L[eve[i].id]);
//			for (ITER j=Set.begin();j!=Set.end();j++)printf("%d ",j->id);printf("\n");
			r=l; r++;
			if (l!=Set.begin()) 
				l--,add(eve[i].id,l->id,++inum);
			if (r!=Set.end())
				add(r->id,eve[i].id,++inum);
		}
		else if (eve[i].f==3)
		{
			Set.erase(L[eve[i].id]);
//			for (ITER j=Set.begin();j!=Set.end();j++)printf("%d ",j->id);printf("\n");
		}
	}
	Topo();
	icnt=0;
	for (int i=1;i<=n;i++) uniq[++icnt]=L[i].a.x,uniq[++icnt]=L[i].b.x;
	sort(uniq+1,uniq+icnt+1);
	icnt=unique(uniq+1,uniq+icnt+1)-uniq-1;
	for (int i=1;i<=n;i++) rank[lst[i]]=i;
	SEG.Build(icnt-1);
	int ans=n,itmp,id,di,l,r;
	for (int i=n;i;i--)
	{
		id=Q[i].first,di=Q[i].second;
		l=Bin(L[id].a.x),r=Bin(L[id].b.x)-1;
		if ((di&1)==d)
		{
			if (di>>1)
			{
				itmp=SEG.Max(l,r);
				if (itmp>rank[id])
					ans=i;
			}
			else
			{
				itmp=SEG.Min(l,r);
				if (itmp<rank[id])
					ans=i;
			}
		}
		SEG.Change(l,r,rank[id]);
	}
//	for (int i=1;i<=icnt-1;i++)
//		printf("%d %d\n",SEG.Max(i,i),SEG.Min(i,i));
	cl(head); inum=0;
	return ans;
}

int main()
{
	Point a,b;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n);
	for (int i=1;i<=n;i++)
	{
		read(a.x); read(a.y); read(b.x); read(b.y);
		if (b<a) swap(a,b);
		L[i]=Line(a,b,i);
	}
	for (int i=1;i<=n;i++)
		read(Q[i].first),read(Q[i].second);
	Ans=Solve(1);
	for (int i=1;i<=n;i++)
	{  
        swap(L[i].a.x,L[i].a.y); L[i].a.y*=-1;
        swap(L[i].b.x,L[i].b.y); L[i].b.y*=-1; 
        if(L[i].b<L[i].a) swap(L[i].a,L[i].b);  
    }
	Ans=min(Ans,Solve(0));  
	printf("%d\n",Ans);
	for (int i=1;i<=n;i++) printf("%d 0\n",lst[i]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值