• codechef Heavy-light Decompositions


    Heavy-light Decompositions Problem Code: HLDOTSSubmit

    All submissions for this problem are available.

    Heavy-light decomposition of a tree is a powerful tool that often helps in the most difficult tree data structure problems.

    Heavy-light decomposition is to be built on a rooted tree. In this problem, the node with the number 1 should be considered the root of a tree. Heavy light decomposition is a colouring of edges of the tree. Each edge is either heavy or light. For each non leaf node (node having degree greater than 1), from all the edges emanating from it into the subtree rooted at this vertex should have exactly one heavy edge.

    The heavy-light decomposition is called correct, if you can reach any node from the root node by using no more that ⌊ log2 N ⌋ light edges, where N is the number of nodes in the tree.

    Given a tree, calculate the number of its' correct heavy-light decompositions. As answer could be very large, please print it modulo 19101995.

    Input

    There is exactly one test case.

    The first line of input consists of a single integer N, denoting the number of the nodes in the tree.

    Each of the following N - 1 lines contains a pair of integers, denoting the numbers of the nodes that are connected with an edge. The nodes are enumerated by positive integers in the range [1; N].

    Output

    Output the number of correct heavy-light decompositions of the given tree. Since this number can be huge, please output it modulo 19101995.

    Constraints

    • (Subtask 1): 1 ≤ N ≤ 20 - 21 point.
    • (Subtask 2): 1 ≤ N ≤ 1000 - 34 points.
    • (Subtask 3): 1 ≤ N ≤ 100000 - 45 points.

    Example

    Input:
    7
    1 2
    3 1
    3 4
    3 5
    2 6
    2 7
    
    Output:
    8
    

    Explanation

    Example case 1. Input is a complete binary tree. It consists of 7 nodes, therefore you can't have more than ⌊log2 7⌋ = ⌊(2.80735492206)⌋ = 2 light edges on the path from the root node to any other one. But the tree's height is 2, so you can choose the decomposition in any way you like. All the decompositions will be correct ones. There are three nodes that has outgoing edges from them (in the direction opposite to the root's one), their numbers are 1, 2 and 3. Each of them has 2 outgoing edges from which you can colour exactly one of them heavy, so overall you'll have 2 * 2 * 2 = 8 options of creating the correct heavy-light decompositions.

     
     
    题意:求从根到任意节点经过的轻链的个数不超过$log_2n$的轻重链划分的方案数。
    一个树dp。
    由于模数是一个合数,所以不能直接用快速幂求逆元,可以用改用前缀后缀和做。
    f是前缀和,g是后缀和。
    注意没有儿子(叶子)和只有一个儿子的特殊情况。
    //Serene
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const long long maxn=1e5+10,mod=19101995;
    long long n,f[maxn][20],g[maxn][20],ans[maxn][20],fa[maxn],sz,fr[2*maxn];
    
    long long aa;char cc;
    long long read() {
        aa=0;cc=getchar();
        while(cc<'0'||cc>'9') cc=getchar();
        while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
        return aa;
    }
    
    long long fir[maxn],nxt[2*maxn],to[2*maxn],e=0;
    void add(long long x,long long y) {
    	to[++e]=y;nxt[e]=fir[x];fir[x]=e;
    	to[++e]=x;nxt[e]=fir[y];fir[y]=e;
    }
    
    long long rs;
    long long qp(long long x,long long k) {
    	rs=1;if(x<=1) return x;
    	while(k) {
    		if(k&1) (rs*=x)%=mod;
    		x=x*x%mod;k>>=1;
    	}
    	return rs;
    }
    
    void dfs(long long pos) {
    	long long z,tt=0,tot;
    	for(long long y=fir[pos];y;y=nxt[y]) {
    		if((z=to[y])==fa[pos]) continue;
    		fa[z]=pos; dfs(z);
    	}
    	for(long long i=0;i<=sz;++i) f[0][i]=1ll;
    	for(long long y=fir[pos];y;fr[nxt[y]]=y,y=nxt[y]) {
    		if((z=to[y])==fa[pos]) continue; tt++;
    		for(long long i=0;i<=sz;++i) (f[tt][i]=f[tt-1][i]*ans[z][i])%=mod;
    	}
    	tot=tt;
    	for(long long i=0;i<=sz;++i) g[tt][i]=1ll;
    	fr[fir[pos]]=0;
    	for(long long y=fr[0];y;y=fr[y]) {
    		if((z=to[y])==fa[pos]) continue; tt--;
    		for(long long i=0;i<=sz;++i) (g[tt][i]=g[tt+1][i]*ans[z][i])%=mod;
    	}
    	if(tot>1) for(long long y=fir[pos];y;y=nxt[y]) {
    		if((z=to[y])==fa[pos]) continue; tt++;
    		for(long long i=1;i<=sz;++i) (ans[pos][i]+=f[tt-1][i-1]*g[tt][i-1]%mod*ans[z][i])%=mod;
    	}
    	else if(!tot)for(long long i=0;i<=sz;++i) ans[pos][i]=1;
    	else {
    		if(to[fr[0]]==fa[pos]) fr[0]=fr[fr[0]];
    		for(long long i=0;i<=sz;++i) ans[pos][i]=ans[to[fr[0]]][i];
    	}
    }
    
    int main() {
    	n=read();long long x,y;
    	sz=(long long)((double)log(n)/(double)log(2)+1e-8);
    	for(long long i=1;i<n;++i) {
    		x=read();y=read();
    		add(x,y);
    	}
    	dfs(1);
    	printf("%lld",ans[1][sz]);
    	return 0;
    }
    /*
    7
    1 2
    3 2
    4 3
    5 1
    6 2
    7 3
    
    right answer:
    6
    */
    

      

    对拍的rand:

    //Serene
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    using namespace std;
    const int maxn=15;
    int n;
    
    int main() {
    	srand((unsigned)time(NULL));
    	n=rand()%maxn+2;int x;
    	printf("%d
    1 2
    ",n);
    	for(int i=3;i<=n;++i) {
    		x=rand()%(i-1)+1;
    		printf("%d %d
    ",i,x);
    	}
    	return 0;
    }
    

      

    弱者就是会被欺负呀
  • 相关阅读:
    编程自学网站
    SQL中Case语句用法
    SQL 综合应用(1.创建临时表,为后续查询所用) 实例_(学生,课程表,选修表)
    SQL 存储过程(学生,课程表,选修表)
    测试角度看公司流程规范对比后篇
    自动化测试技巧之图片验证
    QTP连载四:神一样的参数化方式?
    自动化测试之控件点击
    自动化测试技巧之结果验证
    自动化测试开展的条件
  • 原文地址:https://www.cnblogs.com/Serene-shixinyi/p/7623163.html
Copyright © 2020-2023  润新知