[HNOI2019]多边形
[HNOI2019]多边形
传送门
Solution
可以说是Day1最简单的题目了.
首先\(\text{Orz yyb}\),希望\(yyb\)高考顺利.
首先注意到\((a,c)\)对应着唯一一种方法分解,考虑与\(n\)相连的点将多边形分成了多个形如\([l,r]\)的区间.
每一个区间互相独立,考虑对于一个区间求解.
在一个区间内,显然只有一个点可以进行分解,不妨令它为\(p\),此时可以分治求解.
然后现在每一次操作就形成了一颗二叉树,考虑合并就是把两个不相关的子树按照顺序任意操作,即\(\prod_{i}\binom{siz_ls+siz_rs}{siz_ls}\).不同区间的合并同理.
考虑提前完成一次操作:
- 如果是第一次操作后就和\(n\)相连了,那么直接删除他的贡献然后把他的儿子的贡献加入答案.
- 如果不是上述操作,那么按照\(rotate\)那样旋转后删除增加贡献即可.
关于\(2\)可以自己画图手玩一下,有利于对于题解的理解.
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define re register
#define ll long long
inline int gi()
{
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=400010,Mod=1e9+7;
int n,fac[N],ifac[N],inv[N],tot,siz[N],ch[N][2],fa[N],rt[N],ans=1;
vector<int>G[N];map<pair<int,int>,int>M;
int C(int x,int y){return 1ll*fac[x]*ifac[y]%Mod*ifac[x-y]%Mod;}
int invC(int x,int y){return 1ll*ifac[x]*fac[y]%Mod*fac[x-y]%Mod;}
int merge(int x,int y){return C(x+y,y);}
int invmerge(int x,int y){return invC(x+y,y);}
void divide(int &x,int ff,int l,int r)
{
if(l+1>=r)return;x=++tot;fa[x]=ff;siz[x]=1;
M[make_pair(l,r)]=x;
int p=lower_bound(G[r].begin(),G[r].end(),l+1)-G[r].begin();p=G[r][p];
divide(ch[x][0],x,l,p);divide(ch[x][1],x,p,r);
ans=1ll*ans*merge(siz[ch[x][0]],siz[ch[x][1]])%Mod;
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
int opt;
void print(int cnt,int ans){printf("%d",cnt);if(opt)printf(" %d",ans);putchar('\n');}
int main()
{
opt=gi();
n=gi();fac[0]=inv[0]=inv[1]=ifac[0]=1;
for(int i=1;i<=n<<1;i++)fac[i]=1ll*fac[i-1]*i%Mod;
for(int i=2;i<=n<<1;i++)inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
for(int i=1;i<=n<<1;i++)ifac[i]=1ll*ifac[i-1]*inv[i]%Mod;
for(int i=1;i<=n-3;i++)
{
int x=gi(),y=gi();
G[x].push_back(y);G[y].push_back(x);
}
for(int i=2;i<n;i++)G[i].push_back(i-1),G[i].push_back(i+1);
G[1].push_back(n);G[1].push_back(2);G[n].push_back(1);G[n].push_back(n-1);
for(int i=1;i<=n;i++)sort(G[i].begin(),G[i].end());
for(int i=0,l=G[n].size();i<l-1;i++)divide(rt[i],0,G[n][i],G[n][i+1]);
int sz=0,cnt=n-1-G[n].size();
for(int i=0,l=G[n].size();i<l-1;i++)ans=1ll*ans*merge(sz,siz[rt[i]])%Mod,sz+=siz[rt[i]];
print(cnt,ans);
int m=gi();
while(m--)
{
int a=gi(),b=gi();if(a>b)swap(a,b);
int p=M[make_pair(a,b)];
int pcnt=cnt-(!fa[p]),pans=ans;
if(fa[p])
{
int ff=fa[p],k=ch[ff][1]==p;
pans=1ll*pans*invmerge(siz[ch[ff][0]],siz[ch[ff][1]])%Mod;
pans=1ll*pans*invmerge(siz[ch[p][0]],siz[ch[p][1]])%Mod;
pans=1ll*pans*merge(siz[ch[ff][k^1]],siz[ch[p][k^1]])%Mod;
pans=1ll*pans*merge(siz[ff]-siz[p]+siz[ch[p][k^1]],siz[ch[p][k]])%Mod;
}
else
{
pans=1ll*pans*invmerge(siz[ch[p][0]],siz[ch[p][1]])%Mod;
pans=1ll*pans*invmerge(sz-siz[p],siz[p])%Mod;
pans=1ll*pans*merge(sz-siz[p],siz[ch[p][0]])%Mod;
pans=1ll*pans*merge(sz-siz[p]+siz[ch[p][0]],siz[ch[p][1]])%Mod;
}
print(pcnt,pans);
}
return 0;
}