[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);
    }
}
View Code

 

 

posted @ 2019-04-30 19:00  hfctf0210  阅读(195)  评论(0编辑  收藏  举报