zoukankan      html  css  js  c++  java
  • 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
    ",last);
            }
        }
    }
    
  • 相关阅读:
    NOI2005瑰丽华尔兹
    BZOJ4919[Lydsy1706月赛]大根堆
    BZOJ1097[POI2007]ATR-Tourist Attractions
    Luogu2973 [USACO10HOL]Driving Out the Piggies G
    Luogu5505 JSOI2011分特产
    Luogu1450 HAOI2008硬币购物
    NOI2001 炮兵阵地
    汕头市队赛 SRM 09 A 撕书
    洛谷P1196 银河英雄传说
    洛谷P3144 [USACO16OPEN]关闭农场Closing the Farm
  • 原文地址:https://www.cnblogs.com/jianglangcaijin/p/4197972.html
Copyright © 2011-2022 走看看