bzoj 4541: [Hnoi2016]礦區【平面圖轉對偶圖+生成樹】
阿新 • • 發佈:2019-05-05
ext tdi bool lld printf cer code push main
首先平面圖轉對偶圖,大概思路是每條邊存正反,每個點存出邊按極角排序,然後找每條邊在它到達點的出邊中極角排序的下一個,這樣一定是這條邊所屬最小多邊形的臨邊,然後根據next邊找出所有多邊形,用三角剖分計算面積
然後就比較妙了,把對偶圖隨便搞一個生成樹出來,然後對於每個詢問,如果一條邊是樹邊,那麽如果這條邊在樹上是向上的就加它子樹的和,否則就減
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int N=2000005; int n,m,k,cnt=1,tot,rt,a[N],fa[N],ne[N],c[N]; long long s1[N],s2[N],ans1,ans2; bool v[N],vis[N]; struct dian { double x,y; dian(double X=0,double Y=0) { x=X,y=Y; } dian operator + (const dian &a) const { return dian(x+a.x,y+a.y); } dian operator - (const dian &a) const { return dian(x-a.x,y-a.y); } }p[N]; struct bian { int x,y,id; double a; bian(int X=0,int Y=0,int ID=0) { x=X,y=Y,id=ID,a=atan2(p[y].y-p[x].y,p[y].x-p[x].x); } bool operator < (const bian &b) const { return a<b.a; } }b[N]; vector<bian>f[N],g[N]; int read() { int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(p=='-') f=-1; p=getchar(); } while(p>='0'&&p<='9') { r=r*10+p-48; p=getchar(); } return r*f; } double cj(dian a,dian b) { return a.x*b.y-a.y*b.x; } long long gcd(long long a,long long b) { return !b?a:gcd(b,a%b); } void dfs(int u) { vis[u]=1; for(int i=0;i<g[u].size();i++) if(!vis[g[u][i].y]) { fa[g[u][i].y]=u; v[g[u][i].id]=v[g[u][i].id^1]=1; dfs(g[u][i].y); s1[u]+=s1[g[u][i].y]; s2[u]+=s2[g[u][i].y]; } } int main() { n=read(),m=read(),k=read(); for(int i=1;i<=n;i++) p[i].x=read(),p[i].y=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); cnt++; b[cnt]=bian(x,y,cnt); f[x].push_back(b[cnt]); cnt++; b[cnt]=bian(y,x,cnt); f[y].push_back(b[cnt]); } for(int i=1;i<=n;i++) sort(f[i].begin(),f[i].end()); for(int i=2;i<=cnt;i++) { int nw=lower_bound(f[b[i].y].begin(),f[b[i].y].end(),b[i^1])-f[b[i].y].begin()-1; if(nw<0) nw+=f[b[i].y].size(); ne[i]=f[b[i].y][nw].id; } for(int i=2;i<=cnt;i++) if(!c[i]) { long long mj=0,nw=i,st=b[i].x; c[i]=++tot; while(1) { int tmp=ne[nw]; c[tmp]=tot; if(b[tmp].y==st) break; mj+=cj(p[b[tmp].x]-p[st],p[b[tmp].y]-p[st]); nw=tmp; } s1[tot]=mj*mj,s2[tot]=mj; if(mj<=0) rt=tot; } for(int i=2;i<=cnt;i++) g[c[i]].push_back(bian(c[i],c[i^1],i)); dfs(rt); // for(int i=1;i<=cnt;i++) // cerr<<v[i]<<" ";cerr<<endl; while(k--) { int tot=(read()+ans1)%n+1; for(int i=1;i<=tot;i++) a[i]=(read()+ans1)%n+1; ans1=ans2=0; a[tot+1]=a[1]; for(int i=1;i<=tot;i++) { int nw=f[a[i]][lower_bound(f[a[i]].begin(),f[a[i]].end(),bian(a[i],a[i+1],0))-f[a[i]].begin()].id; if(v[nw]) { if(c[nw]==fa[c[nw^1]]) ans1+=s1[c[nw^1]],ans2+=s2[c[nw^1]]; else ans1-=s1[c[nw]],ans2-=s2[c[nw]]; } } if(ans2<0) ans1*=-1,ans2*=-1; long long g=gcd(ans1,ans2); ans1/=g,ans2/=g; if(ans1&1) ans2<<=1; else ans1>>=1; printf("%lld %lld\n",ans1,ans2); } return 0; }
bzoj 4541: [Hnoi2016]礦區【平面圖轉對偶圖+生成樹】