zoukankan      html  css  js  c++  java
  • [HNOI2016]矿区

    [HNOI2016]矿区

    平面图转对偶图

    方法:

    1.分成正反两个单向边,每个边属于一个面

    2.每个点按照极角序sort出边

    3.枚举每一个边,这个边的nxt就是反边的前一个(这样找到的是面的边逆时针的)

    4.相当有了置换,把每个nxt环找到,加上统一编号,并计算面积

    5.有向面积为负数的是无限域,仅有一个

    6.原来的单向边“旋转90度”,连接两个面

    然后本题再跑一个以无限域为根的生成树

    记录每个原来的边是否是生成树上的边

    并记录生成树子树的S和S^2

    询问:

    如果当前的边是生成树边的话,如果属于的面作为儿子,加上S和S^2,否则减去

    当面的边逆时针求出的,多边形也是逆时针给出的时候,显然是正确的

    (画图理解)

    注意新图的点数是2*n级别的。

     

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define int long long
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    
    const int M=1200000+5;
    const int N=2e5+5;
    const double eps=1e-10;
    int n,m,q;
    struct po{
        ll x,y;
        po(){}
        po(ll xx,ll yy){
            x=xx;y=yy;
        }
        po friend operator -(po a,po b){
            return po(a.x-b.x,a.y-b.y);
        }
        ll friend operator *(po a,po b){
            return a.x*b.y-a.y*b.x;
        }
    }p[N];
    struct edge{
        int x,y,id;
        double du;
        bool friend operator <(edge a,edge b){
            if(fabs(a.du-b.du)<eps) return a.y<b.y;
            return a.du<b.du;
        }
    }e[M];
    int tot=1;
    int pos[M],nxt[M];
    int on[M];
    double an(const po &a,const po &b){//a->b
        return atan2(b.y-a.y,b.x-a.x);
    }
    vector<edge>to[N],b[M];
    void add(int x,int y){
        e[++tot].x=x;e[tot].y=y;
        e[tot].du=atan2(p[y].y-p[x].y,p[y].x-p[x].x);
        e[tot].id=tot; 
        to[x].push_back(e[tot]);
    }
    
    int cnt;
    ll S[M];
    int rt;
    int mem[M];
    void build(){
        for(reg i=1;i<=n;++i) sort(to[i].begin(),to[i].end());
        for(reg i=2;i<=tot;++i){
            // edge now=(edge){e[i].y,e[i].x,i^1,an(p[e[i].y],p[e[i].x])};
            auto it=lower_bound(to[e[i].y].begin(),to[e[i].y].end(),e[i^1]);
            if(it!=to[e[i].y].begin()) --it;
            else it=to[e[i].y].end(),--it;
            nxt[i]=(*it).id;
        }
        for(reg i=2;i<=tot;++i){
            if(pos[i]) continue;
            pos[i]=pos[nxt[i]]=++cnt;
            for(reg j=nxt[i];e[j].y!=e[i].x;j=nxt[j],pos[j]=cnt){
                S[cnt]+=(p[e[j].x]-p[e[i].x])*(p[e[j].y]-p[e[i].x]);
            }
            if(S[cnt]<=0) rt=cnt;
        }
        for(reg i=2;i<=tot;++i){
            b[pos[i]].push_back((edge){pos[i],pos[i^1],i,0});
        }
    }
    ll S2[M];
    int fa[M];
    bool vis[M];
    void dfs(int x){
        // cout<<" xx "<<x<<endl;
        vis[x]=1;
        S2[x]=S[x]*S[x];S[x]<<=1;
        for(reg i=0;i<(int)b[x].size();++i){
            int y=b[x][i].y;
            if(y==fa[x]) continue;
            if(vis[y]) continue;
            fa[y]=x;
            on[b[x][i].id]=on[b[x][i].id^1]=1;
            dfs(y);
            S[x]+=S[y];
            S2[x]+=S2[y];
        }
    }
    ll son,mom;
    ll gcd(ll a,ll b){
        return b?gcd(b,a%b):a;
    }
    int main(){
        rd(n);rd(m);rd(q);
        for(reg i=1;i<=n;++i){
            rd(p[i].x);rd(p[i].y);
        }
        int x,y;
        for(reg i=1;i<=m;++i){
            rd(x);rd(y);add(x,y);add(y,x);
        }
        build();
    //     cout<<" after build "<<endl;
    //     cout<<" cnt "<<cnt<<endl;
    //     prt(pos,2,tot);
    //     prt(nxt,2,tot);
    //     cout<<" rt "<<rt<<endl;
    //  prt(S,1,cnt);
        dfs(rt);
       
        // prt(S2,1,cnt);
    
    
        // prt(on,2,tot);
    
        int k;
        while(q--){
            rd(k);
            k=(k+son)%n+1;
            for(reg i=1;i<=k;++i){
                rd(x);
                x=(x+son)%n+1;
                mem[i]=x;
            }
            int las=mem[k];
            ll up=0,dw=0;
            for(reg i=1;i<=k;++i){
                edge now=(edge){las,mem[i],0,an(p[las],p[mem[i]])};
                auto it=lower_bound(to[las].begin(),to[las].end(),now);
                int id=(*it).id;
                if(on[id]){
                    if(fa[pos[id]]==pos[id^1]) up+=S2[pos[id]],dw+=S[pos[id]];
                    else up-=S2[pos[id^1]],dw-=S[pos[id^1]];
                }
                las=mem[i];
            }
            ll g=gcd(up,dw);
            son=up/g;
            mom=dw/g;
            printf("%lld %lld
    ",son,mom);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/4/13 19:58:12
    */
    View Code

     

  • 相关阅读:
    如何设置QT的窗口图标和exe应用程序图标(两步搞定操作)
    怎么打包发布QT程序(图文详解)
    QT实现读取sps文件并将数据显示在TableView中(复习)
    LeetCode第一题——两数之和
    大型数据库复习
    Android复习
    C#桌面程序设计复习
    WordCount扩展与优化
    第二次作业(WordCount)重制版
    第二次作业(WordCount)
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10720534.html
Copyright © 2011-2022 走看看