zoukankan      html  css  js  c++  java
  • BZOJ4541 HNOI2016矿区(平面图转对偶图)

      考虑先将平面图转化为对偶图。具体地,将无向边拆成两条有向边。每次考虑找到包围一个区域的所有边。对当前考虑的边,找到该边的反向边在该边终点的出边集中,按极角序排序的后继,这条后继边也是包围该区域的边。这样对偶图就建好了。

      考虑怎么用对偶图解决原问题。将外围的无限域也作为对偶图中的一个点,以其为根随便找一棵生成树,计算子树内面积和及面积平方和。对于询问,考虑多边形上每条边,其同时也是对偶图中两点的边。如果该边在生成树中是非树边,扔掉不管;如果是树边,若由父亲指向儿子,则加上儿子权值,否则减掉儿子权值。具体只能感性理解。

      注意对偶图中两点间可能有重边,判断是否为非树边时小心一点。因为这个调一年也是没谁了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #include<vector>
    #include<cassert>
    using namespace std;
    #define ll long long
    #define Vector point
    #define N 400010
    #define M 1200010
    ll gcd(ll n,ll m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,q,b[N],sur[M],nxt[M],t=-1;
    map<int,int> id[N],tag;
    ll lastx,lasty;
    struct point
    {
        int x,y;
        Vector operator +(const Vector&a) const
        {
            return (Vector){x+a.x,y+a.y};
        }
        Vector operator -(const Vector&a) const
        {
            return (Vector){x-a.x,y-a.y};
        }
        ll operator *(const Vector&a) const
        {
            return 1ll*x*a.y-1ll*y*a.x;
        }
        bool operator <(const Vector&a) const
        {
            return atan2(x,y)<atan2(a.x,a.y);
        }
    }a[N];
    struct edge{int x,y;}e[M];
    struct data
    {
        Vector p;int id;
        bool operator <(const data&a) const
        {
            return p<a.p;
        }
    };
    vector<data> c[N];
    namespace newgraph
    {
        int n,p[N],fa[N],t=0,root;
        ll sum[N],sqr[N],area[N];
        struct data{int to,nxt,id;}edge[M];
        void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].id=z,p[x]=t;}
        void dfs(int k)
        {
            sum[k]=area[k]<<1,sqr[k]=area[k]*area[k];
            for (int i=p[k];i;i=edge[i].nxt)
            if (!fa[edge[i].to]&&edge[i].to!=root)
            {
                tag[edge[i].id]=-1,tag[edge[i].id^1]=1;
                fa[edge[i].to]=k;
                dfs(edge[i].to);
                sum[k]+=sum[edge[i].to],sqr[k]+=sqr[edge[i].to];
            }
        }
    }
    void addedge(int x,int y)
    {
        t++,e[t].x=x,e[t].y=y;id[x][y]=t;
        c[x].push_back((data){a[y]-a[x],t});
    }
    void build()
    {
        for (int i=1;i<=n;i++)
        if (c[i].size())
        {
            sort(c[i].begin(),c[i].end());
            for (int j=0;j<c[i].size()-1;j++)
            nxt[c[i][j].id]=c[i][j+1].id;
            nxt[c[i][c[i].size()-1].id]=c[i][0].id;
        }
        for (int i=0;i<(m<<1);i++)
        if (!sur[i])
        {
            ++newgraph::n;
            int x=i;ll y=0;
            do
            {
                sur[x]=newgraph::n;
                y+=a[e[x].x]*a[e[x].y];
                x=nxt[x^1];
            }while (!sur[x]);
            if (y<0) newgraph::root=newgraph::n;
            newgraph::area[newgraph::n]=y;
        }
        for (int i=0;i<(m<<1);i++)
        newgraph::addedge(sur[i],sur[i^1],i);
        newgraph::dfs(newgraph::root);
    }
    signed main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4541.in","r",stdin);
        freopen("bzoj4541.out","w",stdout);
        const char LL[]="%I64d ";
    #else 
        const char LL[]="%lld ";
    #endif
        n=read(),m=read(),q=read();
        for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
        for (int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            addedge(x,y),addedge(y,x);
        }
        build();
        while (q--)
        {
            int t=(read()+lastx)%n+1;
            for (int i=1;i<=t;i++) b[i]=(read()+lastx)%n+1;
            lastx=0,lasty=0;
            for (int i=1;i<=t;i++)
            {
                int x=tag[id[b[i]][b[i%t+1]]];
                if (x)
                {
                    int y=x==1?sur[id[b[i]][b[i%t+1]]]:sur[id[b[i%t+1]][b[i]]];
                    lasty+=x*newgraph::sum[y],lastx+=x*newgraph::sqr[y];
                }
            }
            ll tmp=gcd(lastx,lasty);
            lastx/=tmp,lasty/=tmp;
            printf(LL,lastx),printf(LL,lasty),printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    Nunit单元测试实践
    win2003下安装大程序的补丁
    内存内运行vs05
    vs03无法调试,需要加入debugger组的办法
    js原型类样例
    DOS下建立以日期文件夹备份的批处理
    转flex了,ria的应用看上去很适合企业级应用开发呢
    C#类中使用Session的正确方法
    C#修改connectionStrings的方法
    批量更改目录或者文件名称
  • 原文地址:https://www.cnblogs.com/Gloid/p/10261692.html
Copyright © 2011-2022 走看看