zoukankan      html  css  js  c++  java
  • [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
    ",cnt);else printf("%d %d
    ",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
    ",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
    ",ret);
        }
    }
    View Code

     

  • 相关阅读:
    Asp.net web服务处理程序(第六篇)
    Asp.net 处理程序(第五篇)
    HttpApplication实战大文件上传 (第四篇)
    HttpApplication处理对象与HttpModule处理模块 (第三篇)
    Asp.net管道 (第二篇)
    HTTP -> Asp.net (第一篇)
    C# 计划任务
    认识元数据和IL(下)<第五篇>
    认识元数据和IL(中)<第四篇>
    认识元数据和IL(上) <第三篇>
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10797684.html
Copyright © 2011-2022 走看看