Topcoder--SRM698-Div2 : SubtreeSum

题意 : 给你一棵树,每个节点有点权,树上的每一个联通子图的价值为联通子图中所有节点点权的or和。求这棵树所有联通子图价值和。

显然可以去考虑增量计算,假如我们有了一棵树,在这棵树上加入一个节点会对答案有多少贡献呢?

考虑对于多出来的联通子图,一定且必须包含有新加入的这个节点才是一个没被计算过的联通子图

把加入的这个节点点权拆成二进制来看,对于每一个二进制位为1的位,每个包含该节点的联通子图都有贡献

对于每个二进制为0的位,只有在包含另一个这个位为1的节点时才有贡献

所以可以设计出一个n^2log的算法

代码 :

class SubtreeSum {
    public:
    #define MOD 1000000007
    int head[55],cnt,n;long long w[55];
    bool open[55];long long ret;long long k;
    struct Edge{
        int to,next;
    }e[205];
    inline void insert(int a,int b) {
        e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b;
        e[++cnt].next=head[b];head[b]=cnt;e[cnt].to=a;
    }

    void init() {
        memset(head,0,sizeof(head));cnt=0;
        ret=0;
    }

    bool vis[55];

    int Cdfs(int v) {
        long long ret=1;vis[v]=1;
        for(int i=head[v];i;i=e[i].next) if(!vis[e[i].to])
            ret=ret*(Cdfs(e[i].to)+1)%MOD;
        return ret;
    }
    int comp(int bit,int v) {
        memset(vis,0,sizeof(vis));
        for(int i=0;i<=n;i++)
            if(!open[i]||w[i]>>bit&1) vis[i]=1;
        vis[v]=0;
        return Cdfs(v);
    }
    void dfs(int v) {
        for(int j=0;j<30;j++)
            if(w[v]>>j&1) {
                k=comp(31,v);k*=1<<j;
                k%=MOD;ret=(ret+k)%MOD;
            }
            else {
                k=comp(31,v)-comp(j,v);k*=1<<j;
                k%=MOD;ret=(ret+k)%MOD;
            }
        open[v]=1;
        for(int i=head[v];i;i=e[i].next)
            if(!open[e[i].to]) dfs(e[i].to);
    }

    int getSum(vector<int> p, vector<int> x) {
        init();
        n=p.size();
        for(int i=0;i<n;i++) insert(p[i],i+1);
        for(int i=0;i<=n;i++) w[i]=x[i];
        dfs(0);
        return ret;
    }

};
时间: 2024-10-09 23:06:57

Topcoder--SRM698-Div2 : SubtreeSum的相关文章

topcoder SRM628 div2 500(转)

Problem Statement      We have three types of brackets: "()", "[]", and "{}". We are now interested in some special strings. A string is special if all the following conditions hold: Each character of the string is one of the

Topcoder SRM632 DIV2 解题报告

250:乱搞 解题代码: 1 // BEGIN CUT HERE 2 /* 3 4 */ 5 // END CUT HERE 6 #line 7 "RunningAroundPark.cpp" 7 #include <cstdlib> 8 #include <cctype> 9 #include <cstring> 10 #include <cstdio> 11 #include <cmath> 12 #include <

topcoder 649 DIV2

8 A:模拟 9:B:终于看懂题目... 题意:最多分解K次 每分钟一个数可以分解成两个数 或者-1: 关键字:DP,记忆花搜索. DP[I][J]=min(dp[i][j],1+max(dp[ii][jj],dp[i-ii][j-jj-1]); 1 #include<iostream> 2 #include <string>  3 #include <vector>  4 #include<cmath>  5 #include <string.h&g

[Topcoder]SRM632 div2 题解

TC第一次解出三题--当了次room leader-- 感觉这次的题比较弱,代码量也很小,都是在拼手速了 250 RunningAroundPark 题意很好懂,一圈跑道上有N棵树,现给你遇到这些树的顺序,问最少需要多少走圈才能遇到相应的序列 直接判断a[i]<=a[i+1]即可 首先假定走了一圈 #include <cstdlib> #include <cctype> #include <cstring> #include <cstdio> #inc

Topcoder SRM631 DIV2 解题报告

250:网格有两种颜色,网格中一列最长的连续的颜色相同的最大值. 解题思路:暴力. 解题代码: // BEGIN CUT HERE /* */ // END CUT HERE #line 7 "TaroGrid.cpp" #include <cstdlib> #include <cctype> #include <cstring> #include <cstdio> #include <cmath> #include <

topcoder 643 DIV2

太弱了,太弱了! A:基本的判断吧,然后就是边界问题,写了好久,结果发现时房间第二个交的.. B:真心跪了,还好想出来了,思路想的太慢太慢,结果交上去,落后太多,不过HACK时很多人挂了, 这也是DIV1的A题.做法是: 如果对于一个long long 的数质因数分解师很难做到的. 但是题目告诉了m/2个数,m是分解后质因数的个数. 然后我们想先刷法求出1-10^6的质因数. 如果n有大于10^6的质因数最多2个(n<=10^18)对吧. 然后已经写出了1个,一定会写出一个. 所以 我们对其用1

Topcoder SRM633 DIV2 解题报告

250:乱搞. 1 // BEGIN CUT HERE 2 /* 3 4 */ 5 // END CUT HERE 6 #line 7 "Target.cpp" 7 #include <cstdlib> 8 #include <cctype> 9 #include <cstring> 10 #include <cstdio> 11 #include <cmath> 12 #include <algorithm> 1

Topcoder SRM655 DIV2 950 NineEasy 状压 + 数位 dp

题意:要你构造一个n位的数子 ,给你m(1-5)个询问,每一次询问取一些位数的数组成一个新数且这个数 %9 ==  0 , 问你要满足这m个询问的数字有多少个(允许前缀0). 解题思路:把每一种情况状压,得到一个最多  9x9x9x9x9 的情况,然后根据 每个数的询问决定状态转移方程. 解题代码: 1 // BEGIN CUT HERE 2 /* 3 4 */ 5 // END CUT HERE 6 #line 7 "NineEasy.cpp" 7 #include <cstd

ACM学习历程—TopCoder SRM691 Div2

这是我的第一次打TC,感觉打的一般般吧.不过TC的题目确实挺有意思的. 由于是用客户端打的,所以就不发题目地址了. 300分的题: 这题大意是有一段序列只包含+和数字0~9. 一段序列的操作是,从头扫到尾,遇到+就对计数器+1.遇到数字就计算abs(num-count)的值,并加到sum中. 题目要求重新排序序列,使得sum最小. 由于是abs,最小值自然是0,于是就是要构造0. 由于计数器只会网上增,所以数字我肯定从小到大排,于是对于某个数,计数器不足这个数,那么就需要增加计数器,否则就计算a

Topcoder SRM655 DIV2 250 BichromeBoard 水

题意:给你一个网格图 ,每个网格中是W,B,两种颜色和 ? 表示未知,相同颜色的网格不能相邻,问你能否满足条件 解题思路:W和B的位置 和 (i+j) 的奇偶有关. 解题代码: 1 // BEGIN CUT HERE 2 /* 3 4 */ 5 // END CUT HERE 6 #line 7 "BichromeBoard.cpp" 7 #include <cstdlib> 8 #include <cctype> 9 #include <cstring&