题目大意:给定平面上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 可持久化线段树+分治
原文地址:http://blog.csdn.net/popoqqq/article/details/44494063