【題解】Luogu P5288 [HNOI2019]多邊形

原題傳送門

HN的題目就是毒瘤

咱們有如下猜測:

1.最後全部的線都連到了n號點上

2.最小步數應該爲n-3-已經連到n號點的線段數量

原本有些邊\((a_i,n)\)會將整個圖分割成不少個區間。對於一個區間\([l,r]\)\(l,r\)之間一定存在一條邊,而且必定存在點\(mid\)\((mid,l),mid(mid,r)\)的邊,因此咱們珂以用一次旋轉使得\((l,r)\)變成\((mid,n)\),這樣這個區間有珂以分紅兩個子區間,珂以建出二叉樹。一直如此,直到\(r=l+1\)爲止。咱們如今就要考慮如何計算方案數,父節點的旋轉必定在子節點的旋轉以前,但子節點間互不干擾,因此就是一個插入排序方案數的問題,明顯兩個子樹順序影響就是把答案乘上\(\frac{(size(ls)+size(rs))!}{size(ls)!size(rs)!}\)

最後要記得不一樣區間之間也有合併的貢獻

咱們如今要考慮修改:

1.\((a,c)\)旋轉後正好爲\((b,n)\),就至關於將一棵樹根節點的兩個子樹做爲新的樹,而且刪除原來的根節點,對最小步數的影響爲-1,對次數的影響也很簡單(此處就不贅述,不會的珂以看代碼)

2.\((a,c)\)旋轉後變成了\((b,d) (d \neq n)\),這個操做像splay的rotate,具體見圖片,對最小步數沒有影響,對次數的影響見代碼

#include <bits/stdc++.h>
#define N 100005
#define mod 1000000007 
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline int fastpow(register int a,register int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=1ll*res*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return res;
}
vector<int> E[N];
inline void add(register int u,register int v)
{
    E[u].push_back(v),E[v].push_back(u);
}
int W,n,m;
int fac[N],invf[N];
int fa[N],ls[N],rs[N],sz[N];
int tot=0,sum=0,ans=1;
map<pair<int,int>,int> M;
inline int calc(register int n,register int m)
{
    return 1ll*fac[n+m]*invf[n]%mod*invf[m]%mod;
}
inline int calcinv(register int n,register int m)
{
    return 1ll*invf[n+m]*fac[n]%mod*fac[m]%mod;
}
inline void dfs(register int &x,register int l,register int r,register int f)
{
    if(l+1==r)
        return;
    x=++tot;
    M[make_pair(l,r)]=x;
    fa[x]=f;
    int mid=*(--lower_bound(E[l].begin(),E[l].end(),r));
    dfs(ls[x],l,mid,x),dfs(rs[x],mid,r,x);
    sz[x]=sz[ls[x]]+sz[rs[x]]+1;
    ans=1ll*ans*calc(sz[ls[x]],sz[rs[x]])%mod;
}
int main()
{
    fac[0]=1;
    for(register int i=1;i<N;++i)
        fac[i]=1ll*fac[i-1]*i%mod;
    invf[N-1]=fastpow(fac[N-1],mod-2);
    for(register int i=N-1;i;--i)
        invf[i-1]=1ll*invf[i]*i%mod;
    W=read(),n=read();
    for(register int i=1;i<n;++i)
        add(i,i+1);
    add(1,n);
    for(register int i=1;i<=n-3;++i)
    {
        int u=read(),v=read();
        add(u,v);
    }
    for(register int i=1;i<=n;++i)
        sort(E[i].begin(),E[i].end());
    for(register int i=0;i<E[n].size()-1;++i)
    {
        int x=0;
        dfs(x,E[n][i],E[n][i+1],0);
        ans=1ll*ans*calc(sum,sz[x])%mod;
        sum+=sz[x];
    }
    if(W)
        write(sum),putchar(' '),write(ans),puts("");
    else
        write(sum),puts("");
    m=read();
    while(m--)
    {
        int a=read(),b=read(),x=M[make_pair(a,b)];
        if(fa[x])
        {
            int f=fa[x],now=ans;
            now=1ll*now*calcinv(sz[ls[x]],sz[rs[x]])%mod;
            now=1ll*now*calcinv(sz[ls[f]],sz[rs[f]])%mod;
            now=1ll*now*calc(sz[rs[x]],sz[rs[f]])%mod;
            now=1ll*now*calc(sz[ls[x]],sz[rs[x]]+sz[rs[f]]+1)%mod;
            if(W)
                write(sum),putchar(' '),write(now),puts("");
            else
                write(sum),puts("");
        }
        else
        {
            int now=ans;
            now=1ll*now*calcinv(sz[ls[x]],sz[rs[x]])%mod;
            now=1ll*now*calcinv(sum-sz[x],sz[x])%mod;
            now=1ll*now*calc(sum-sz[x],sz[ls[x]])%mod;
            now=1ll*now*calc(sum-sz[x]+sz[ls[x]],sz[rs[x]])%mod;
            if(W)
                write(sum-1),putchar(' '),write(now),puts("");
            else
                write(sum-1),puts("");
        }
    }
    return 0;
}
相關文章
相關標籤/搜索