[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('\n');}

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\n",son,mom);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/4/13 19:58:12
*/
View Code

 

posted @ 2019-04-16 22:28  *Miracle*  阅读(436)  评论(0编辑  收藏  举报