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);

        }

    }

}

 

你可能感兴趣的:(link)