[HNOI2016]矿区
生活随笔
收集整理的這篇文章主要介紹了
[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->breturn 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?
轉載于:https://www.cnblogs.com/Miracevin/p/10720534.html
總結
以上是生活随笔為你收集整理的[HNOI2016]矿区的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷P1090 合并果子
- 下一篇: C#流程控制语句--跳转语句(break