zoukankan      html  css  js  c++  java
  • Gym102012G Rikka with Intersections of Paths

    题意

    (T) 组数据,每组数据给定一棵 (n) 个点的树和 (m) 条路径,求选出 (k) 条给定路径使得至少有两条交于一点的方案数,对 (10^9+7) 取模。

    ( exttt{Data Range:}1leq Tleq 200,1leq nleq 3 imes 10^5,2leq mleq 3 imes 10^5,2leq kleq m)

    题解

    这种题都不能一次 AC,而且还是犯的弱智错误,我太菜了。

    考虑这样一个结论:如果两条路径交于一些点,那么这些点中的某一个肯定是这两条路径中一条的两个端点的 LCA。

    我们枚举这样一个端点,然后容斥。设 (u_x) 为这些路径中经过 (x) 的数量,(v_x) 为这些路径中两个端点的 LCA 为 (x) 的数量,那么答案为

    [sumlimits_{i=1}^{n}inom{u_i}{k}-inom{u_i-v_i}{k} ]

    然后 (v) 是很容易维护的,(u) 树上差分一下就好了。

    所以我们容易看出邪王真眼是最强的!!!

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    typedef long long int li;
    const ll MAXN=3e5+51,MOD=1e9+7;
    struct Edge{
        ll to,prev;
    }; 
    Edge ed[MAXN<<1];
    ll test,n,m,kk,tot,from,to,lca,res;
    ll last[MAXN],u[MAXN],v[MAXN],depth[MAXN],anc[MAXN][20],fact[MAXN];
    ll finv[MAXN],f[MAXN],diff[MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline ll qpow(ll base,ll exponent)
    {
        ll res=1;
        while(exponent)
        {
            if(exponent&1)
            {
                res=(li)res*base%MOD;
            }
            base=(li)base*base%MOD,exponent>>=1;
        }
        return res;
    }
    inline void setup(ll cnt)
    {
        fact[0]=fact[1]=finv[0]=1;
        for(register int i=2;i<=cnt;i++)
        {
            fact[i]=(li)fact[i-1]*i%MOD;
        }
        finv[cnt]=qpow(fact[cnt],MOD-2);
        for(register int i=cnt-1;i;i--)
        {
            finv[i]=(li)finv[i+1]*(i+1)%MOD;
        }
    }
    inline ll binom(ll m,ll n)
    {
        return m<n?0:(li)fact[m]*finv[n]%MOD*finv[m-n]%MOD;
    }
    inline void addEdge(ll from,ll to)
    {
        ed[++tot].prev=last[from];
        ed[tot].to=to;
        last[from]=tot;
    }
    inline void dfs(ll node,ll fa)
    {
        depth[node]=depth[anc[node][0]=fa]+1;
        for(register int i=last[node];i;i=ed[i].prev)
        {
            ed[i].to!=fa?dfs(ed[i].to,node):(void)1;
        }
    }
    inline void LCASetup()
    {
        for(register int j=1;j<20;j++)
        {
            for(register int i=1;i<=n;i++)
            {
                anc[i][j]=anc[anc[i][j-1]][j-1];
            }
        }
    }
    inline ll LCA(ll x,ll y)
    {
        depth[x]<depth[y]?swap(x,y):(void)1;
        for(register int i=19;i>=0;i--)
        {
            depth[anc[x][i]]>=depth[y]?x=anc[x][i]:1;
        }
        for(register int i=19;i>=0;i--)
        {
            anc[x][i]!=anc[y][i]?x=anc[x][i],y=anc[y][i]:1;
        }
        return x==y?x:anc[x][0];
    }
    inline void dfs2(ll node,ll fa)
    {
        ll to;
        for(register int i=last[node];i;i=ed[i].prev)
        {
            (to=ed[i].to)!=fa?dfs2(to,node),diff[node]+=diff[to]:1;
        }
    }
    inline void solve()
    {
        n=read(),m=read(),kk=read(),tot=0,memset(last,0,sizeof(last));
        for(register int i=0;i<n-1;i++)
        {
            from=read(),to=read(),addEdge(from,to),addEdge(to,from);
        }
        dfs(1,0),LCASetup(),memset(f,0,sizeof(f)),memset(diff,0,sizeof(diff));
        for(register int i=1;i<=m;i++)
        {
            u[i]=read(),v[i]=read(),f[lca=LCA(u[i],v[i])]++;
            diff[u[i]]++,diff[v[i]]++,diff[lca]--,diff[anc[lca][0]]--;
        }
        dfs2(1,0),res=0;
        for(register int i=1;i<=n;i++)
        {
            res=(res+(binom(diff[i],kk)-binom(diff[i]-f[i],kk)+MOD)%MOD)%MOD;
        }
        printf("%d
    ",res);
    }
    int main()
    {
        test=read(),setup(300010);
        for(register int i=0;i<test;i++)
        {
            solve();
        }
    }
    
  • 相关阅读:
    Linux下MySql多实例免安装部署
    linux apf防火墙安装配置
    Fedora Yum命令查询软件包及清除缓存
    什么时候使用e.target.content和e.target as MovieClip
    帧频计数器
    设置播放器的品质
    访问文件名连续的mc、txt、btn
    Sound 音乐工具类【转载】
    确定字符串中、出现特定字符串的次数
    数组var _list:Array = new Array({logType:"1"});
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13617718.html
Copyright © 2011-2022 走看看