[HNOI2019]多边形

[HNOI2019]多边形

传送门

Luogu

Solution

可以说是Day1最简单的题目了.
首先\(\text{Orz yyb}\),希望\(yyb\)高考顺利.
首先注意到\((a,c)\)对应着唯一一种方法分解,考虑与\(n\)相连的点将多边形分成了多个形如\([l,r]\)的区间.
每一个区间互相独立,考虑对于一个区间求解.
在一个区间内,显然只有一个点可以进行分解,不妨令它为\(p\),此时可以分治求解.
然后现在每一次操作就形成了一颗二叉树,考虑合并就是把两个不相关的子树按照顺序任意操作,即\(\prod_{i}\binom{siz_ls+siz_rs}{siz_ls}\).不同区间的合并同理.
考虑提前完成一次操作:

  1. 如果是第一次操作后就和\(n\)相连了,那么直接删除他的贡献然后把他的儿子的贡献加入答案.
  2. 如果不是上述操作,那么按照\(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;
}
posted @ 2020-02-24 23:24  fexuile  阅读(134)  评论(0编辑  收藏  举报