首页 > 代码库 > BZOJ 2758 Blinker的噩梦(扫描线+熟练剖分+树状数组)

BZOJ 2758 Blinker的噩梦(扫描线+熟练剖分+树状数组)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2758

题意:平面上有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的所有多边形。维护的时候将要维护的多边形分成上下两部分。每个多边形的上部的标号就是自己,下部的标号为包含自己的最小多边形。每次假设从当前多边形向上有一条射线,那么第一次交到的就是包含该多边形的多边形(注意我们维护的信息是下部的标号为包含自己的最小多边形)。每次一个多边形不在当前要维护区间时删掉。

 

const double inf=1e20;const int N=600005;struct point{    double x,y;    point(double _x=0,double _y=0)    {        x=_x;        y=_y;    }};struct Figure{    int type;    vector<point> up,down;    double x,y,r;    int v;    pair<double,double> read()    {        char op[5];        scanf("%s",op);        if(‘C‘==op[0])        {            type=0;            scanf("%lf%lf%lf%d",&x,&y,&r,&v);            return MP(x-r,x+r);        }        type=1;        vector<point> tmp;        double Min=inf,Max=-inf;        int minId,maxId;        int n=myInt();        for(int i=0;i<n;i++)        {            double x,y;            scanf("%lf%lf",&x,&y);            tmp.pb(point(x,y));            if(x>Max) Max=x,maxId=i;            if(x<Min) Min=x,minId=i;        }        if(maxId<minId)        {            for(int i=minId;i>=maxId;i--) down.pb(tmp[i]);            for(int i=minId;i<n;i++) up.pb(tmp[i]);            for(int i=0;i<=maxId;i++) up.pb(tmp[i]);        }        else        {            for(int i=minId;i<=maxId;i++) up.pb(tmp[i]);            for(int i=minId;i>=0;i--) down.pb(tmp[i]);            for(int i=n-1;i>=maxId;i--) down.pb(tmp[i]);        }        v=myInt();        return MP(Min,Max);    }    int find(vector<point> a,double x)    {        for(int i=0;i+1<a.size();i++)        {            if(a[i].x<=x&&x<=a[i+1].x) return i;        }    }    double intersect(point L,point R,double x)    {        return L.y+(x-L.x)/(R.x - L.x)*(R.y-L.y);    }    double getInterval(double xx,int dir)    {        if(0==type)        {            if(fabs(xx-(x-r))<=0.001||fabs(xx-(x+r))<=0.001)            {                return y;            }            double tmp=sqr(r)-sqr(x-xx);            double d=sqrt(tmp);            if(dir) return y+d;            return y-d;        }        if(xx==up[0].x||xx==up.back().x)        {            double Max=-inf,Min=inf;            for(int i=0;i<up.size();i++) if(xx==up[i].x) Max=max(Max,up[i].y);            for(int i=0;i<down.size();i++) if(xx==down[i].x) Min=min(Min,down[i].y);            if(!dir) return Min;            return Max;        }        if(dir)        {            int u=find(up,xx);            return intersect(up[u],up[u+1],xx);        }        int d=find(down,xx);        return intersect(down[d],down[d+1],xx);    }};struct Query{    int type,l,r;};struct sweepPoint{    double x;    int id,dir;    sweepPoint(double _x=0,int _id=0,int _dir=0)    {        x=_x;        id=_id;        dir=_dir;    }};Figure G[N];sweepPoint Q[N];int qNum;Query query[N];point p[N];int pNum;int n,m;vector<int> g[N];void add(int x,int y){    g[x].pb(y);}double curX;struct myPair{    int id,dir,belong;    myPair(double id=0,int dir=0,int belong=0)    {        this->id=id;        this->dir=dir;        this->belong=belong;    }    friend int operator<(const myPair &a,const myPair &b)    {        if(a.id==b.id&&a.dir!=2&&b.dir!=2) return a.dir<b.dir;        double x=(2==a.dir)?p[a.id].y:G[a.id].getInterval(curX,a.dir);        double y=(2==b.dir)?p[b.id].y:G[b.id].getInterval(curX,b.dir);        return x<y;    }};set<myPair> T;myPair L[N],R[N];int cmp(sweepPoint a,sweepPoint b){    if(fabs(a.x-b.x)<1e-8) return a.dir<b.dir;    return a.x<b.x;}void init(){    sort(Q+1,Q+qNum+1,cmp);    int K=n+pNum+1;    for(int i=1;i<=qNum;i++)    {        curX=Q[i].x;        if(0==Q[i].dir)        {            myPair tmp=myPair(Q[i].id,1,Q[i].id);            T.insert(tmp);            R[Q[i].id]=tmp;            set<myPair>::iterator it=T.find(tmp);            it++;            int belong=it==T.end()?K:it->belong;            tmp=myPair(Q[i].id,0,belong);            T.insert(tmp);            L[Q[i].id]=tmp;            add(belong,Q[i].id);        }        else if(1==Q[i].dir)        {            T.erase(L[Q[i].id]);            T.erase(R[Q[i].id]);        }        else if(2==Q[i].dir)        {            myPair tmp=myPair(Q[i].id,2,0);            set<myPair>::iterator it=T.lower_bound(tmp);            if(it==T.end()) add(K,Q[i].id+n);            else add(it->belong,Q[i].id+n);        }    }}int d[N];int son[N];int fa[N];void DFS(int u){    son[u]=1;    for(int i=0;i<SZ(g[u]);i++)    {        int v=g[u][i];        fa[v]=u;        DFS(v);        son[u]+=son[v];    }}int pool[N];int poolCount;int *S[N];int pos[N],root[N],id,listLen[N];void dfs(int u,int rt){    id++;    root[u]=rt;    pos[u]=id;    listLen[rt]++;    int s=0;    for(int i=0;i<SZ(g[u]);i++)    {        int v=g[u][i];        if(son[v]>son[s]) s=v;    }    if(!s) return;    dfs(s,rt);    for(int i=0;i<SZ(g[u]);i++)    {        int v=g[u][i];        if(v!=s) dfs(v,v);    }}void add(int rt,int x,int val){    while(x<=listLen[rt])    {        S[rt][x]^=val;        x+=x&-x;    }}int cal(int t){    int rtPos=pos[root[t]];    int x=pos[t]-rtPos+1;    int rt=root[t];    int ans=0;    while(rt)    {        while(x) ans^=S[rt][x],x-=x&-x;        int t=fa[rt];        int rtPos=pos[root[t]];        x=pos[t]-rtPos+1;        rt=root[t];    }    return ans;}int main(){    n=myInt();    m=myInt();    for(int i=1;i<=n;i++)    {        pair<double,double> tmp=G[i].read();        Q[++qNum]=sweepPoint(tmp.first,i,0);        Q[++qNum]=sweepPoint(tmp.second,i,1);    }    for(int i=1;i<=m;i++)    {        char op[5];        scanf("%s",op);        if(‘Q‘==op[0])        {            pNum++; scanf("%lf%lf",&p[pNum].x,&p[pNum].y);            pNum++; scanf("%lf%lf",&p[pNum].x,&p[pNum].y);            query[i].type=1;            query[i].l=pNum-1;            query[i].r=pNum;            Q[++qNum]=sweepPoint(p[pNum-1].x,pNum-1,2);            Q[++qNum]=sweepPoint(p[pNum].x,pNum,2);        }        else        {            query[i].type=0;            scanf("%d%d",&query[i].l,&query[i].r);        }    }    init();    for(int i=1;i<=n;i++) d[i]=G[i].v;    DFS(n+pNum+1);    dfs(n+pNum+1,n+pNum+1);    for(int i=1;i<=n+pNum+1;i++)    {        if(root[i]==i)        {            S[i]=pool+poolCount;            poolCount+=listLen[i]+2;        }    }    for(int i=1;i<=n;i++)    {        int rtPos=pos[root[i]];        int p=pos[i];        int x=p-rtPos+1;        add(root[i],x,d[i]);    }    int last=0;    for(int i=1;i<=m;i++)    {        if(0==query[i].type)        {            int t=query[i].l;            int rtPos=pos[root[t]];            int p=pos[t];            int x=p-rtPos+1;            add(root[t],x,d[t]);            d[t]=query[i].r;            add(root[t],x,d[t]);        }        else if(1==query[i].type)        {            int x=cal(query[i].l+n);            int y=cal(query[i].r+n);            last^=x^y;            printf("%d\n",last);        }    }}

 

BZOJ 2758 Blinker的噩梦(扫描线+熟练剖分+树状数组)