码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 3658 Jabberwocky 可持久化线段树+分治

时间:2015-03-20 22:10:33      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj3658   可持久化线段树   分治   

题目大意:给定平面上n个点,一共有k种颜色,要求选定一条线段,并选取线段正上方或正下方的所有点,要求不能出现所有颜色的点,求最多选择多少点

正解是双向链表+树状数组?

让我们来点优雅的做法


由于不能出现所有颜色的点 因此一定有至少一种颜色不出现 我们可以枚举这个不出现的颜色

现在我们搞出所有极大子矩形

这个分治就好了。。。


假设我们现在求的是一条线段下方的点 那么我们考虑一条直线从下往上走 遇到禁止的点就分成两段 继续

那么我们利用分治来模拟这个过程

定义Solve(l,r)为处理横坐标在[l,r]区间内的点

那么我们寻找横坐标在[l,r]区间内的y值最小的点p

如果不存在这个点 就直接用左上角为(l,INF),右下角为(r,-INF)的矩形来更新答案

如果存在这个点 就用左上角为(l,p.y),右下角为(r,-INF)的矩形来更新答案,然后递归处理[l,p.x-1]和[p.x+1,y]


那么我们怎么统计某个矩形中有多少点呢?

主席树搞一搞就可以辣!!


一开始脑残写了个树套树T到死。。。


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;

namespace Functional_Segtree{

	struct Segtree{
		Segtree *ls,*rs;
		int val;
		void* operator new (size_t,Segtree *_,Segtree *__,int ___);
	}*tree[M],mempool[2000000],*C=mempool,*root;

	void* Segtree :: operator new (size_t,Segtree *_,Segtree *__,int ___)
	{
		C->ls=_;
		C->rs=__;
		C->val=___;
		return C++;
	}

	Segtree* Insert(Segtree *p,int x,int y,int pos)
	{
		int mid=x+y>>1;
		if(x==y)
			return new (0x0,0x0,p->val+1)Segtree;
		if(pos<=mid)
			return new (Insert(p->ls,x,mid,pos),p->rs,p->val+1)Segtree;
		else
			return new (p->ls,Insert(p->rs,mid+1,y,pos),p->val+1)Segtree;
	}

	int Query(Segtree *p1,Segtree *p2,int x,int y,int l,int r)
	{
		int mid=x+y>>1;
		if(x==l&&y==r)
			return p2->val - p1->val;
		if(r<=mid)
			return Query(p1->ls,p2->ls,x,mid,l,r);
		if(l>mid)
			return Query(p1->rs,p2->rs,mid+1,y,l,r);
		return Query(p1->ls,p2->ls,x,mid,l,mid) + Query(p1->rs,p2->rs,mid+1,y,mid+1,r);
	}

	void Initialize()
	{
		C=mempool;
		tree[0]=new (0x0,0x0,0)Segtree;
		tree[0]->ls=tree[0]->rs=tree[0];
	}

}

struct Point{
	int x,y;
	bool operator < (const Point &p) const
	{
		return x < p.x;
	}
}points[M],_points[M];

bool Compare1(int x,int y)
{
	return points[x].y < points[y].y;
}

bool Compare2(int x,int y)
{
	if(x==0) return true;
	if(y==0) return false;
	return points[x].y > points[y].y;
}

namespace Segment_Tree{
	struct Segtree{
		Segtree *ls,*rs;
		int max_pos;
		void* operator new (size_t);
	}mempool[M<<1],*C=mempool,*root;

	void Initialize()
	{
		C=mempool;
		root=0x0;
	}

	void* Segtree :: operator new (size_t)
	{
		C->ls=C->rs=0x0;
		C->max_pos=0;
		return C++;
	}

	void Insert(Segtree *&p,int x,int y,int pos,bool(&Compare)(int,int))
	{
		int mid=x+y>>1;
		if(!p) p=new Segtree;
		if(x==y)
		{
			p->max_pos=max(p->max_pos,pos,Compare);
			return ;
		}
		if(points[pos].x<=mid)
			Insert(p->ls,x,mid,pos,Compare);
		else
			Insert(p->rs,mid+1,y,pos,Compare);
		p->max_pos=max( (p->ls?p->ls->max_pos:0) , (p->rs?p->rs->max_pos:0) , Compare );
	}

	int Query(Segtree *p,int x,int y,int l,int r,bool(&Compare)(int,int))
	{
		int mid=x+y>>1;
		if(!p) return 0;
		if(x==l&&y==r)
			return p->max_pos;
		if(r<=mid)
			return Query(p->ls,x,mid,l,r,Compare);
		if(l>mid)
			return Query(p->rs,mid+1,y,l,r,Compare);
		return max( Query(p->ls,x,mid,l,mid,Compare) , Query(p->rs,mid+1,y,mid+1,r,Compare) , Compare );
	}
}

int n,k,ans;
int a[M],c[M];
pair<int,int*> b[M];

bool Compare(int x,int y)
{
	return a[x] < a[y];
}

void Divide_And_Conquer1(int l,int r)
{
	if(l>r) return ;
	int mid=Segment_Tree::Query(Segment_Tree::root,1,n,l,r,Compare1);
	if(!mid)
	{
		ans=max(ans,Functional_Segtree::Query(Functional_Segtree::tree[l-1],Functional_Segtree::tree[r],1,n,1,n));
		return ;
	}
	if(points[mid].y<n)
		ans=max(ans,Functional_Segtree::Query(Functional_Segtree::tree[l-1],Functional_Segtree::tree[r],1,n,points[mid].y+1,n));
	Divide_And_Conquer1(l,points[mid].x-1);
	Divide_And_Conquer1(points[mid].x+1,r);
}

void Divide_And_Conquer2(int l,int r)
{
	if(l>r) return ;
	int mid=Segment_Tree::Query(Segment_Tree::root,1,n,l,r,Compare2);
	if(!mid)
	{
		ans=max(ans,Functional_Segtree::Query(Functional_Segtree::tree[l-1],Functional_Segtree::tree[r],1,n,1,n));
		return ;
	}
	if(points[mid].y>1)
		ans=max(ans,Functional_Segtree::Query(Functional_Segtree::tree[l-1],Functional_Segtree::tree[r],1,n,1,points[mid].y-1));
	Divide_And_Conquer2(l,points[mid].x-1);
	Divide_And_Conquer2(points[mid].x+1,r);
}

int main()
{
	
	freopen("jabber.in","r",stdin);
	freopen("jabber.out","w",stdout);
	
	int T,i,j;
	srand(19980402);
	for(cin>>T;T;T--)
	{
		Functional_Segtree::Initialize();
		ans=0;
		cin>>n>>k;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d%d",&points[i].x,&points[i].y,&a[i]);
			c[i]=i;
		}

		sort(c+1,c+n+1,Compare);

		for(i=1;i<=n;i++)
			b[i]=make_pair(points[i].x,&points[i].x);
		sort(b+1,b+n+1);
		int tot=0;
		for(i=1;i<=n;i++)
		{
			if(i==1||b[i].first!=b[i-1].first)
				++tot;
			*b[i].second=tot;
		}

		for(i=1;i<=n;i++)
			b[i]=make_pair(points[i].y,&points[i].y);
		sort(b+1,b+n+1);
		tot=0;
		for(i=1;i<=n;i++)
		{
			if(i==1||b[i].first!=b[i-1].first)
				++tot;
			*b[i].second=tot;
		}
		
		memcpy(_points,points,sizeof points);
		sort(_points+1,_points+n+1);
		for(j=1,i=1;i<=n;i++)
		{
			Functional_Segtree::tree[i]=Functional_Segtree::tree[i-1];
			for(;_points[j].x==i;j++)
				Functional_Segtree::tree[i]=Functional_Segtree::Insert(Functional_Segtree::tree[i],1,n,_points[j].y);
		}

		//上半部分
		for(j=1,i=1;i<=k;i++)
		{
			Segment_Tree::Initialize();
			for(;j<=n&&a[c[j]]==i;j++)
				Segment_Tree::Insert(Segment_Tree::root,1,n,c[j],Compare1);
			Divide_And_Conquer1(1,n);
		}

		//下半部分
		for(j=1,i=1;i<=k;i++)
		{
			Segment_Tree::Initialize();
			for(;j<=n&&a[c[j]]==i;j++)
				Segment_Tree::Insert(Segment_Tree::root,1,n,c[j],Compare2);
			Divide_And_Conquer2(1,n);
		}

		cout<<ans<<endl;
	}
	return 0;
}



BZOJ 3658 Jabberwocky 可持久化线段树+分治

标签:bzoj   bzoj3658   可持久化线段树   分治   

原文地址:http://blog.csdn.net/popoqqq/article/details/44494063

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!