[扫描线 树链剖分 树状数组] BZOJ2758 [SCOI2012]Blinker的噩梦

扫描线 

一般扫描线的做法就是想象一根线向某个方向扫过,进入的进入,出去的出去,用一个set维护序列或是结合线段树,当然最恶心的就是加上计算几何

但是落实到这题上就是各种鬼畜乱搞,只能膜大神

省选前做难题的结果是——到处翻题解,程序越改越像


题意:平面上有n个多边形(凸包和圆)。任意两个多边形AB只有两种关系:(1)A包含B或者B包含A;(2)AB的公共面积为0。每个多边形有一个值x。m个查询。分两种:(1)修改某个多边形的值;(2)从一点s走到另一点t。每次走出一个多边形或者进入一个多边形时,都要抑或上该多边形的值。输出走到t时的值。(由抑或的性质和本题定义可得这个值跟走的路经无关)

思路:首先我们发现,这些多边形构成了一棵树。另外设定义某一点p的值S(p)等于包含该点的所有多边形的值的抑或。那么答案为S(s)^S(t)。对应于那个树上,就是s和t到根的值的抑或和。如果我们建成了这棵树,那么分别维护:(1)修改某点的值;(2)查询某点到根的抑或值。这个可以用树链剖分,之后每个链用树状数组维护。

那么现在的问题来了,这个树怎么建?扫描线。保存多边形的最左最右。排序。按照x升序处理。维护包含当前x的所有多边形。维护的时候将要维护的多边形分成上下两部分。每个多边形的上部的标号就是自己,下部的标号为包含自己的最小多边形。每次假设从当前多边形向上有一条射线,那么第一次交到的就是包含该多边形的多边形(注意我们维护的信息是下部的标号为包含自己的最小多边形)。每次一个多边形不在当前要维护区间时删掉。

——来自http://www.cnblogs.com/jianglangcaijin/p/4197972.html


很坑!! 有半径为零的圆


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<set>
#include<vector>
#define V G[p].v
#define eps 1e-6
#define inf 1e20
using namespace std;
 
inline int dcmp(double a,double b)
{
    if (fabs(a-b)<eps) return 0;
    if (a<b) return -1;
    return 1;
}
 
inline void Getchar(char &x)
{
    for (x=getchar();x!='Q' && x!='C' && x!='P';x=getchar());
}
 
inline double sqr(double x){
    return x*x;
}
 
const int MAXN=300000+5;
 
namespace BIT{
    #define lowbit(x) ((x)&-(x))
    int c[MAXN];
    int maxn;
    inline void init(int n){
        maxn=n;
    }
    inline void change(int x,int r){
        for (int i=x;i<=maxn;i+=lowbit(i))
            c[i]^=r;
    }
    inline int sum(int x){
        int ret=0;
        for (int i=x;i;i-=lowbit(i))
            ret^=c[i];
        return ret;
    }
    inline int sum(int l,int r){
        if (l>r) return 0;
        return sum(r)^sum(l-1);
    }
}
 
struct edge{
    int u,v;
    int next;
};
 
edge G[MAXN];
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 size[MAXN],depth[MAXN],fat[MAXN];
int clk,tid[MAXN],top[MAXN];
 
inline void dfs(int u,int fa){
    fat[u]=fa; size[u]=1; depth[u]=depth[fa]+1;
    for (int p=head[u];p;p=G[p].next)
        if (V!=fa)
            dfs(V,u),size[u]+=size[V];
}
 
inline void find(int u,int fa,int z){
    tid[u]=++clk; top[u]=z; 
    int maximum=0,son=0;
    for (int p=head[u];p;p=G[p].next)
        if (V!=fa && maximum<size[V])
            maximum=size[son=V];
    if (son) find(son,u,z);
    for (int p=head[u];p;p=G[p].next)
        if (V!=fa && V!=son)
            find(V,u,V);
}
 
int val[MAXN];
inline void Change(int u,int r){
    BIT::change(tid[u],val[tid[u]]);
    val[tid[u]]=r;
    BIT::change(tid[u],r);
}
 
inline int Query(int u,int v){
    int ret=0;
    for (;top[u]!=top[v];u=fat[top[u]])
    {
        if (depth[top[u]]<depth[top[v]]) swap(u,v);
        ret^=BIT::sum(tid[top[u]],tid[u]);
    }
    if (depth[u]<depth[v]) swap(u,v);
    ret^=BIT::sum(tid[v],tid[u]);
    ret^=val[tid[v]];
    return ret;
}
 
struct Point{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) { }
}; 
 
struct Figure{
    int type;
    Point up[35],down[35];
    double x,y,r;
    int val;
    int cnt1,cnt2;
    pair<double,double> read(){
        char order;
        Getchar(order);
        if (order=='C'){
            type=0;
            scanf("%lf%lf%lf",&x,&y,&r);
            scanf("%d",&val);
            return pair<double,double>(x-r,x+r);
        }
        type=1;
        Point tmp[35];
        double Min=1e20,Max=-1e20;
        int n,maxId,minId;
        scanf("%d",&n);
        for (int i=0;i<n;i++)
        {
            scanf("%lf%lf",&tmp[i].x,&tmp[i].y);
            if (Min>tmp[i].x) Min=tmp[i].x,minId=i;
            if (tmp[i].x>Max) Max=tmp[i].x,maxId=i;
        }
        if(maxId<minId)
        {
            for(int i=minId;i>=maxId;i--) down[cnt2++]=tmp[i];
            for(int i=minId;i<n;i++) up[cnt1++]=tmp[i];
            for(int i=0;i<=maxId;i++) up[cnt1++]=tmp[i];
        }
        else
        {
            for(int i=minId;i<=maxId;i++) up[cnt1++]=tmp[i];
            for(int i=minId;i>=0;i--) down[cnt2++]=tmp[i];
            for(int i=n-1;i>=maxId;i--) down[cnt2++]=tmp[i];
        }
        scanf("%d",&val);
        return make_pair(Min,Max);
    }
    int find(Point *a,int size,double x)
    {
        for(int i=0;i+1<size;i++)
            if(a[i].x<=x&&x<=a[i+1].x) 
                return i;
    }
    double Inter(Point L,Point R,double x)
    {
        return L.y+(x-L.x)/(R.x - L.x)*(R.y-L.y);
    }
    double Inter(double curx,int dir)
    {
        if(type==0)
        {
            if(fabs(curx-(x-r))<=1e-3||fabs(curx-(x+r))<=1e-3)
            {
                return y;
            }
            double tmp=sqr(r)-sqr(x-curx);
            double d=sqrt(tmp);
            if(dir) return y+d;
            return y-d;
        }
        if(curx==up[0].x||curx==up[cnt1-1].x)
        {
            double Max=-inf,Min=inf;
            for(int i=0;i<cnt1;i++) if(curx==up[i].x) Max=max(Max,up[i].y);
            for(int i=0;i<cnt2;i++) if(curx==down[i].x) Min=min(Min,down[i].y);
            if(!dir) return Min;
            return Max;
        }
        if(dir)
        {
            int u=find(up,cnt1,curx);
            return Inter(up[u],up[u+1],curx);
        }
        else
        {
            int d=find(down,cnt2,curx);
            return Inter(down[d],down[d+1],curx);
        }
    }
}F[100005];
 
struct event{
    double x;
    int id;
    int f;
    bool operator < (const event &B) const{
        return dcmp(x,B.x)==0?f<B.f:x<B.x;
    }
}eve[500005];
int tot;
 
struct Query{
    int x,y;
    int type;
}Que[100005];
 
int n,m,ptot;
Point P[200005];
 
double Curx;
 
struct data{
    int id,dir,fat;
    data(int id=0,int dir=0,int fat=0):id(id),dir(dir),fat(fat) { }
};
bool operator < (const data &A,const data &B){
    if (A.id==B.id) return A.dir<B.dir;
    double y1=A.id>n?P[A.id-n].y:F[A.id].Inter(Curx,A.dir);
    double y2=B.id>n?P[B.id-n].y:F[B.id].Inter(Curx,B.dir);
    return y1<y2;
}
 
int Krt;
set<data> Set;
typedef set<data>::iterator ITER;
data U[100005],D[100005];
 
inline void Init()
{
    sort(eve+1,eve+tot+1);
    data tmp;
    for (int i=1;i<=tot;i++)
    {
        Curx=eve[i].x;
        if (eve[i].f==-1)
        {
            tmp=data(eve[i].id,1,eve[i].id);
            Set.insert(tmp);
            U[eve[i].id]=tmp;
            ITER it=Set.find(tmp); it++;
            int belong=it==Set.end()?Krt:it->fat;
             
            tmp=data(eve[i].id,0,belong);
            Set.insert(tmp);
            D[eve[i].id]=tmp;
             
            add(belong,eve[i].id,++inum);
        }
        else if (eve[i].f==1)
        {
            Set.erase(U[eve[i].id]);
            Set.erase(D[eve[i].id]);
        }
        else if (eve[i].f==0)
        {
            tmp=data(eve[i].id,1,0);
            ITER it=Set.lower_bound(tmp);
            if(it==Set.end()) 
                add(Krt,eve[i].id,++inum);
            else
                add(it->fat,eve[i].id,++inum);
        }
    }
}
 
int main()
{
    char order;
    freopen("t.in","r",stdin);
    freopen("t.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
		pair<double,double> itmp=F[i].read();
        eve[++tot].x=itmp.first; eve[tot].id=i; eve[tot].f=-1;
        eve[++tot].x=itmp.second; eve[tot].id=i; eve[tot].f=1;
    }
    for (int i=1;i<=m;i++)
    {
        Getchar(order);
        if (order=='C')
        {
            Que[i].type=0;
            scanf("%d%d",&Que[i].x,&Que[i].y);  
        }
        else if (order=='Q')
        {
            Que[i].type=1;
            ptot++; scanf("%lf%lf",&P[ptot].x,&P[ptot].y);
            eve[++tot].x=P[ptot].x; eve[tot].id=ptot+n; eve[tot].f=0;
            ptot++; scanf("%lf%lf",&P[ptot].x,&P[ptot].y);
            eve[++tot].x=P[ptot].x; eve[tot].id=ptot+n; eve[tot].f=0;
            Que[i].x=ptot-1,Que[i].y=ptot;
        }
    }
    Krt=ptot+n+1;
    Init();
    dfs(Krt,0);
    find(Krt,0,Krt);
    BIT::init(Krt);
    for (int i=1;i<=n;i++) Change(i,F[i].val);
    int lastans=0,_x,_y;
    for (int i=1;i<=m;i++)
    {
        if (Que[i].type==0)
        {
            Change(Que[i].x,Que[i].y);
        }
        else if (Que[i].type==1)
        {
            lastans^=Query(Que[i].x+n,Que[i].y+n);
            printf("%d\n",lastans);
        }
    }
    return 0;
}



这道题做了我整整一天多,没上课,真的是一天多,哭晕

我打了一上午的maker,调试了半上午。

最后maker似乎还有多多少少的问题

放弃了他

还是决定放一下

凸包计算几何什么的...


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#include<cstring>
using namespace std;
typedef long long ll;

struct Point{
	int x,y;
	Point(int x=0,int y=0):x(x),y(y) { } 
	bool operator < (const Point &b) const{
		return x<b.x || x==b.x && y<b.y;
	}
};
int s[105];

inline ll Cross(Point p1,Point p2,Point p0)
{
	return ((ll)(p1.x-p0.x))*(p2.y-p0.y)-((ll)(p2.x-p0.x))*(p1.y-p0.y);
}

int cnt;

inline void Qhull(Point *P,Point *hull,int l,int r,Point a,Point b){
	int i=l-1,j=r+1,x=l;
	for (int k=l;k<=r;k++)
		if (s[k]>s[x] || s[k]==s[x] && P[x]<P[k])
			x=k;
	Point y=P[x];
	for (int k=l;k<=r;k++)
	{
		s[++i]=Cross(P[k],a,y);
		if (s[i]>0) swap(P[k],P[i]); else s[i--]=0;
	}
	for (int k=r;k>=l;k--)
	{
		s[--j]=Cross(P[k],y,b);
		if (s[j]>0) swap(P[j],P[k]); else s[j++]=0;
	}
	if (l<=i) Qhull(P,hull,l,i,a,y);
	hull[++cnt]=y;
	if (j<=r) Qhull(P,hull,j,r,y,b);
}

inline int Pd(Point *p,int n,Point a)
{
	ll tag=Cross(p[n],p[1],a);
	if (tag==0) return -1;
	for (int i=1;i<n;i++)
	{
		ll tmp=Cross(p[i],p[i+1],a);
		if (tmp==0)
			return -1;
		if ((tmp>0 && tag<0) || (tmp<0 && tag>0)) 
			return 0;
	}
	return 1;
}

inline int random(int x,int y)
{
	return x+rand()*rand()%(y-x+1);
}

int _N,_M;
Point AP[1005][105];
int tot[1005];

inline void Maker(Point *rp,int rn,int xs)
{
	if (xs>=200 || _N>2000) return;
	int maxx=-1<<30,maxy=-1<<30,minx=1<<30,miny=1<<30,midx,midy;
	for (int i=1;i<=rn;i++) { maxx=max(maxx,rp[i].x); maxy=max(maxy,rp[i].y); minx=min(minx,rp[i].x); miny=min(miny,rp[i].y); }
	if ((maxx-minx)<20 || (maxy-miny)<20) return;
	midx=(maxx+minx)>>1;
	midy=(maxy+miny)>>1;
	Point p[5][25];
	int n[5]={0};
	Point h[25];
	int x1,x2,y1,y2;
	for (int i=1,flag=0;i<=4 && flag<=1;i++)
		if (rand()%1000)
		{
			++flag;
			if (i==1){
				x1=minx,x2=midx; y1=miny,y2=midy;
			}
			else if (i==2){
				x1=minx,x2=midx; y1=midy+1,y2=maxy;
			}
			else if (i==3){
				x1=midx+1,x2=maxx; y1=miny,y2=midy;
			}
			else if (i==4){
				x1=midx+1,x2=maxx; y1=midy+1,y2=maxy;
			}
//		x1=minx,x2=maxx,y1=miny,y2=maxy;
//		for (int i=1;i<=1;i++){
			n[i]=rand()%10+2;
			int ta=0;
			for (int j=1;j<=n[i] && !ta;j++)
			{
				int c1=0;
				do
				{
					if (++c1==10000) break;
					p[i][j]=Point(random(x1,x2),random(y1,y2));
					if (Pd(rp,rn,p[i][j])!=1) continue;
					int f=0,tmp;
					for (int k=1;k<i && !f;k++)
						if (n[k])
							if (Pd(p[k],n[k],p[i][j])!=0)
								f=1;
					if (!f) break;
				}while(1);
				if (c1==1000) ta=1;
			}
			if (!ta)
			{
				int x=1;
				for (int j=1;j<=n[i];j++) if (p[i][j]<p[i][x]) x=j;
				swap(p[i][1],p[i][x]);
				cnt=0;
				memset(s,0,sizeof(s));
				h[++cnt]=p[i][1];
				Qhull(p[i],h,2,n[i],p[i][1],p[i][1]);
				if (cnt>2)
				{
					_N++;
					for (int j=1;j<=cnt;j++) { p[i][j]=h[j]; AP[_N][j]=h[j]; }
					n[i]=tot[_N]=cnt;
					Maker(p[i],n[i],xs+1);
				}
				else
					n[i]=0;
			}
			else
				n[i]=0;
		}
}

int main()
{
	unsigned long long Time=time(0);
	srand(Time);
//	freopen("t.in","r",stdin);
	freopen("t.in","w",stdout);
	Point P[5],a,b;
	int maxx=100,maxy=100,minx=-100,miny=-100;
	P[1]=Point(minx,maxy);
	P[2]=Point(maxx,maxy);
	P[3]=Point(maxx,miny);
	P[4]=Point(minx,miny);
	Maker(P,4,0);
	printf("%d %d\n",_N,_M=rand()%10+1);
	for (int i=1;i<=_N;i++)
	{
		printf("P %d",tot[i]);
		for (int j=1;j<=tot[i];j++)
			printf(" %.1lf %.1lf",AP[i][j].x/10.0,AP[i][j].y/10.0);
		printf(" %d\n",rand()*rand());
	}
	while (_M--)
	{
		int order=rand()%4+1;
		if (_N && order==1)
		{
			printf("C %d %d\n",rand()%_N+1,rand()*rand());
		}
		else
		{
			do
			{
				a=Point(random(minx,maxy),random(miny,maxy));
				int flag=0,tmp;
				for (int k=1;k<=_N && !flag;k++)
					if ((tmp=Pd(AP[k],tot[k],a))==-1)
						flag=1;
				if (!flag) break;
			}while(1);
			do
			{
				b=Point(random(minx,maxy),random(miny,maxy));
				int flag=0,tmp;
				for (int k=1;k<=_N && !flag;k++)
					if ((tmp=Pd(AP[k],tot[k],a))==-1)
						flag=1;
				if (!flag) break;
			}while(1);
			printf("Q %.1lf %.1lf %.1lf %.1lf\n",a.x/10.0,a.y/10.0,b.x/10.0,b.y/10.0);
		}
	}
	printf("%u\n",Time);
	return 0;
}



你可能感兴趣的:([扫描线 树链剖分 树状数组] BZOJ2758 [SCOI2012]Blinker的噩梦)