[HNOI2019]多边形
题解:首先根据题意,可以猜到结论:最终图一定是从n号点向其他所有点各连一条边。然后发现一个结论:每次把图中一条(a,b)边连成(c,n)。然后50pts的劣质O(mnlogn)的分治做法就有了:对于分治区间[l,r],可以枚举从n号点是否有在(l,r)间的剖边,如果有则直接分治,如果没有,则找到能转换为剖边的一条边,然后分治。就是寻找过程比较麻烦。合并两边答案时,cnt=cntL+cntR+0/1,当需要转换边则为1,反之为0;ans=ansL*ansR*C(cntL+cntR,cntR),这样每次修改就再做一遍。
但其实这个做法如果能把单次修改做到log级别,就能通过了。不难发现是此过程是二叉树(其实也就类似于上述做法),但如何完成修改操作呢?然后能够发现该操作类似于splay,即rotate一个点,然后除以原来的贡献,乘上新贡献即可。注意旋转后一边为n,这时候cnt-=1,然后把原本的方案数除掉,再乘上直接把左右两个儿子当成被和n相连的边分割的方案数就行了。复杂度O((n+m)logn)。
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> pii; const int N=2e5+7,mod=1e9+7; int tp,n,m,ans,cnt,tot,fac[N],inv[N],fa[N],rt[N],sz[N],ch[N][2]; vector<int>G[N]; map<pii,int>h; int C(int a,int b){return 1ll*fac[a+b]*inv[a]%mod*inv[b]%mod;} int iC(int a,int b){return 1ll*inv[a+b]*fac[a]%mod*fac[b]%mod;} void divide(int &x,int f,int l,int r) { if(r-l<=1)return; x=++tot,sz[x]=1,fa[x]=f; int p=G[r][lower_bound(G[r].begin(),G[r].end(),l+1)-G[r].begin()]; h[pii(l,r)]=x; divide(ch[x][0],x,l,p),divide(ch[x][1],x,p,r); sz[x]+=sz[ch[x][0]]+sz[ch[x][1]]; ans=1ll*ans*C(sz[ch[x][0]],sz[ch[x][1]])%mod; } int main() { scanf("%d%d",&tp,&n); inv[0]=inv[1]=1;for(int i=2;i<=2*n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; fac[0]=1;for(int i=1;i<=2*n;i++)fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod; for(int i=1;i<=n;i++)G[i].push_back(i%n+1),G[i%n+1].push_back(i); for(int i=1,x,y;i<=n-3;i++)scanf("%d%d",&x,&y),G[x].push_back(y),G[y].push_back(x); for(int i=1;i<=n;i++)sort(G[i].begin(),G[i].end()); ans=1; for(int i=0;i<G[n].size()-1;i++)divide(rt[i],0,G[n][i],G[n][i+1]); int sum=0; for(int i=0;i<G[n].size()-1;i++)ans=1ll*ans*C(sum,sz[rt[i]])%mod,sum+=sz[rt[i]]; cnt=n-1-G[n].size(); if(!tp)printf("%d\n",cnt);else printf("%d %d\n",cnt,ans); scanf("%d",&m); while(m--) { int x,y,p,ret;scanf("%d%d",&x,&y); if(x>y)swap(x,y); p=h[pii(x,y)]; if(!tp){printf("%d\n",cnt-(fa[p]?0:1));continue;} else printf("%d ",cnt-(fa[p]?0:1)); ret=ans; if(fa[p]) { int f=fa[p],o=ch[f][1]==p; ret=1ll*ret*iC(sz[ch[p][0]],sz[ch[p][1]])%mod; ret=1ll*ret*iC(sz[ch[f][0]],sz[ch[f][1]])%mod; ret=1ll*ret*C(sz[ch[f][o^1]],sz[ch[p][o^1]])%mod; ret=1ll*ret*C(sz[f]-sz[p]+sz[ch[p][o^1]],sz[ch[p][o]])%mod; } else{ ret=1ll*ret*iC(sz[ch[p][0]],sz[ch[p][1]])%mod; ret=1ll*ret*iC(sum-sz[p],sz[p])%mod; ret=1ll*ret*C(sum-sz[p],sz[ch[p][0]])%mod; ret=1ll*ret*C(sum-sz[p]+sz[ch[p][0]],sz[ch[p][1]])%mod; } printf("%d\n",ret); } }