Topcoder--SRM698-Div2 : SubtreeSum
Posted ihopenot
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; } };
以上是关于Topcoder--SRM698-Div2 : SubtreeSum的主要内容,如果未能解决你的问题,请参考以下文章