bzoj4541 [Hnoi2016]礦區
Description
平面上的礦區劃分成了若幹個開發區域。簡單地說,你可以將礦區看成一張連通的平面圖,平面圖劃分為了若幹平面塊,每個平面塊即為一個開發區域,平面塊之間的邊界必定由若幹整點(坐標值為整數的點)和連接這些整點的線段組成。每個開發區域的礦量與該開發區域的面積有關:具體而言,面積為s的開發區域的礦量為 s^2。現在有 m 個開采計劃。每個開采計劃都指定了一個由若幹開發區域組成的多邊形,一個開采計劃的優先度被規定為礦量的總和÷開發區域的面積和;例如,若某開采計劃指定兩個開發區域,面積分別為 a和b,則優先度為(a^2+b^2)/(a+b)。由於平面圖是按照劃分開發區域邊界的點和邊給出的,因此每個開采計劃也只說明了其指定多邊形的邊界,並未詳細指明是哪些開發區域(但很明顯,只要給出了多邊形的邊界就可以求出是些開發區域)。你的任務是求出每個開采計劃的優先度。為了避免精度問題,你的答案必須按照分數的格式輸出,即求出分子和分母,且必須是最簡形式(分子和分母都為整數,而且都消除了最大公約數;例如,若礦量總和是 1.5,面積和是2,那麽分子應為3,分母應為4;又如,若礦量和是 2,面積和是 4,那麽分子應為 1,分母應為 2)。由於某些原因,你必須依次對每個開采計劃求解(即下一個開采計劃會按一定格式加密,加密的方式與上一個開采計劃的答案有關)。具體的加密方式見輸入格式。
Input
第一行三個正整數 n,m,k,分別描述平面圖中的點和邊,以及開采計劃的個數。接下來n行,第 i行(i=1,2,…,n)有兩個整數x_i, y_i, 表示點i的坐標為(x_i, y_i)。接下來m行,第 i行有兩個正整數a,b,表示點a和b 之間有一條邊。接下來一行若幹個整數,依次描述每個開采計劃。每個開采計劃的第一個數c指出該開采計劃由開發區域組成的多邊形邊界上的點的個數為d=(c+P) mod n + 1;接下來d個整數,按逆時針方向描述邊界上的每一個點:設其中第i個數為z_i,則第i個點的編號為(z_i+P) mod n + 1。其中P是上一個開采計劃的答案中分子的值;對於第 1 個開采計劃,P=0。
Output
對於每個開采計劃,輸出一行兩個正整數,分別描述分子和分母。
Sample Input
9 14 50 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
1 2
2 3
5 6
7 8
8 9
1 4
4 7
5 8
3 6
6 9
4 8
1 5
2 6
6 8
3 3 0 4 7 1 3 4 6 4 8 0 4 3 6 2 3 8 0 4 6 2 5 0 4 5 7 6 3
Sample Output
1 11 2
1 1
9 10
HINT
輸入文件給出的9個點和14條邊描述的平面圖如下所示:
第一個開采計劃,輸入的第1個值為3,所以該開采計劃對應的多邊形有(3+0) mod 8 +1=4個點,將接下的4個數3,0,4,7,分別代入(z_i+0) mod n + 1得到4個點的編號為4,1,5,8。計算出第一個開采計劃的分子為1,分母為1。類似地,可計算出余下開采計劃的多邊形的點數和點的編號:第二個開采計劃對應的多邊形有3個點,編號分別為5, 6, 8。第三個開采計劃對應的多邊形有6個點,編號分別為1, 2, 6, 5, 8, 4。第四個開采計劃對應的多邊形有5個點,編號分別為1, 2, 6, 8, 4。第五個開采計劃對應的多邊形有6個點,編號分別為1, 5, 6, 8, 7, 4。
對於100%的數據,n, k ≤ 2×10^5, m ≤ 3n-6, |x_i|, |y_i| ≤ 3×10^4。所有開采計劃的d之和不超過2×10^6。保證任何開采計劃都包含至少一個開發區域,且這些開發區域構成一個連通塊。保證所有開發區域的礦量和不超過 2^63-1。保證平面圖中沒有多余的點和邊。保證數據合法。由於輸入數據量較大,建議使用讀入優化。
正解:平面圖轉對偶圖+生成樹+$hash$。
終於把$HNOI2016$做完了。。
感覺這題也不是那麽不可做?雖然我還是什麽都不會。。
首先我們考慮把這個平面圖轉成對偶圖,怎樣把平面圖轉成對偶圖呢?
把所有無向邊拆成兩條,然後對於每個點,把以它為起點的邊極角排序一下。
每次從一條還不屬於任意一個域的邊開始找,找到這條邊的終點後,終點變成起點,找在這個點上這條反邊的上一個極角序的邊。
然後重復上一個操作,直到回到最初的起點,這就是平面圖的一個域了。
我們把域和域之間連邊,以無界域為根結點做一棵生成樹,統計子樹面積和和子樹的面積平方和。
如何找到無界域?我們要求每一個域的面積,這個用向量叉積求比較方便。如果這個域的有向面積$<=0$,那麽它就是無界域。
然後我們詢問的時候,找出每一條邊,這個用$hash$就能快速找到了。
首先,如果這條邊是非樹邊,那麽我們可以直接忽略掉。否則對於每一條邊,我們考慮它的域是它反邊所在域的兒子還是父親。
如果是兒子,那麽加上它所在的域的權值和,否則減去它反邊所在域的權值和。
證明不太會。。畫一下圖感性理解下就好。。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define M (1200010) 6 #define N (200010) 7 #define rhl (2341687) 8 9 using namespace std; 10 11 struct point{ 12 int x,y; 13 il point operator - (const point &a) const{ 14 return (point){x-a.x,y-a.y}; 15 } 16 }p[N]; 17 18 struct edge{ 19 int u,v,id; double ang; 20 il bool operator < (const edge &a) const{ 21 return ang<a.ang; 22 } 23 }g[M]; 24 25 struct E{ int nt,to,id; }G[M]; 26 struct H{ int nt,x,y,id; }hsh[M]; 27 28 vector <edge> e[N]; 29 30 int hd[rhl+10],head[M],vis[M],fa[M],in[M],bl[M],nxt[M],ask[M<<1],n,m,k,rt,num,cnt,ecnt,hcnt; 31 ll sp[M],s[M],P,Q; 32 33 il int gi(){ 34 RG int x=0,q=1; RG char ch=getchar(); 35 while ((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘) ch=getchar(); 36 if (ch==‘-‘) q=-1,ch=getchar(); 37 while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar(); 38 return q*x; 39 } 40 41 il ll gcd(RG ll a,RG ll b){ return b ? gcd(b,a%b) : a; } 42 43 il ll cross(RG point a,RG point b){ 44 return 1LL*a.x*b.y-1LL*a.y*b.x; 45 } 46 47 il void insert(RG int a,RG int b){ 48 RG double ang=atan2(p[b].y-p[a].y,p[b].x-p[a].x); 49 ++num,g[num]=(edge){a,b,num,ang},e[a].push_back(g[num]); return; 50 } 51 52 il void Insert(RG int from,RG int to,RG int id){ 53 G[++ecnt]=(E){head[from],to,id},head[from]=ecnt; return; 54 } 55 56 il void ins(RG int from,RG int x,RG int y,RG int id){ 57 hsh[++hcnt]=(H){hd[from],x,y,id},hd[from]=hcnt; return; 58 } 59 60 il void add(RG int x,RG int y,RG int id){ 61 RG int wyh=(1LL*x*N+y)%rhl; ins(wyh,x,y,id); return; 62 } 63 64 il int get(RG int x,RG int y){ 65 RG int wyh=(1LL*x*N+y)%rhl; 66 for (RG int i=hd[wyh];i;i=hsh[i].nt) 67 if (hsh[i].x==x && hsh[i].y==y) return hsh[i].id; 68 return 0; 69 } 70 71 il void dfs(RG int x){ 72 vis[x]=1,sp[x]=s[x]*s[x],s[x]<<=1; RG int v; 73 for (RG int i=head[x];i;i=G[i].nt){ 74 v=G[i].to; if (vis[v]) continue; 75 fa[v]=x,in[G[i].id]=in[G[i].id^1]=1; 76 dfs(v),sp[x]+=sp[v],s[x]+=s[v]; 77 } 78 return; 79 } 80 81 int main(){ 82 #ifndef ONLINE_JUDGE 83 freopen("mine.in","r",stdin); 84 freopen("mine.out","w",stdout); 85 #endif 86 n=gi(),m=gi(),k=gi(),num=1; RG int x,y; 87 for (RG int i=1;i<=n;++i) x=gi(),y=gi(),p[i]=(point){x,y}; 88 for (RG int i=1;i<=m;++i) x=gi(),y=gi(),insert(x,y),insert(y,x); 89 for (RG int i=1,sz;i<=n;++i){ 90 sort(e[i].begin(),e[i].end()),sz=e[i].size(); 91 for (RG int j=1;j<sz;++j) nxt[e[i][j].id]=e[i][j-1].id; 92 nxt[e[i][0].id]=e[i][sz-1].id; 93 } 94 for (RG int i=2;i<=num;++i){ 95 if (bl[i]) continue; bl[i]=bl[nxt[i^1]]=++cnt; 96 for (RG int now=nxt[i^1];g[now].v!=g[i].u;now=nxt[now^1],bl[now]=cnt) 97 s[cnt]+=cross(p[g[now].u]-p[g[i].u],p[g[now].v]-p[g[i].u]); 98 if (s[cnt]<=0) rt=cnt; 99 } 100 for (RG int i=2;i<=num;++i) Insert(bl[i],bl[i^1],i),add(g[i].u,g[i].v,g[i].id); dfs(rt); 101 for (RG int q=1,d;q<=k;++q){ 102 d=(gi()+P)%n+1; for (RG int i=1;i<=d;++i) ask[i]=(gi()+P)%n+1; 103 ask[d+1]=ask[1],P=Q=0; 104 for (RG int i=1,now;i<=d;++i){ 105 now=get(ask[i],ask[i+1]); if (!in[now]) continue; 106 if (fa[bl[now]]==bl[now^1]) P+=sp[bl[now]],Q+=s[bl[now]]; 107 else P-=sp[bl[now^1]],Q-=s[bl[now^1]]; 108 } 109 RG ll gg=gcd(P,Q); P/=gg,Q/=gg; printf("%lld %lld\n",P,Q); 110 } 111 return 0; 112 }
bzoj4541 [Hnoi2016]礦區