HDU 5739 Fantasia
来源:互联网 发布:淘宝运营提成比例 编辑:程序博客网 时间:2024/06/05 19:24
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5739
题目大意:给你一个森林,森林中的每个点有固定的价值,森林中树的价值为树中所有点的乘积,森林的价值为森林中所有树价值的总和,从1到n每次删除一个点,设删完点后森林的价值*对应得点的序号为Gi,问Gi(i从1到n)的总和是多少
解题思路:
预处理:预处理出每个树的价值,将每一个无根树通过DFS变为有根树,在DFS的过程中求出每一个点及其下所有子节点的乘积存储到数组val中,求出每一个点的dfs序存储到pre中,求出每一个点的low值,low值就是此点能连接到的dfs序中标号最小的点,存储到low中(不懂low值或pre是什么的请见刘汝佳入门经典-训练指南上的312页或者百度双连通分量,推荐前者)
具体操作:对于某个树,当要删除树中点 i 时,判断其所有子节点low[j]是否大于等于pre[i],如果是则说明删除点 i 后其子节点j和其下的所有点会变成单独的连通块,即刚才预处理出的val[j],用一个值ans2统计所有的val[j] ,再用一个值ans1表示删除点 i 后剩余节点的价值,用树的价值乘以i价值 的逆元和所有val[j]的逆元 就可以了。多个树稍微变变就好了。
AC代码:
#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#include <vector>#include <algorithm>#define RI(N) scanf("%d",&(N))#define RII(N,M) scanf("%d %d",&(N),&(M))#define RIII(N,M,K) scanf("%d %d %d",&(N),&(M),&(K))#define mem(a) memset((a),0,sizeof(a))using namespace std;const int inf=1e9+7;const int inf1=-1*1e9;double EPS=1e-10;typedef long long LL;int pre[100005];//节点的dfs序int n,m;vector<int>G[100005];//图int weight[100005];//节点权值int treeNumber=0;int tree[100005];//每个子节点对应的树的标号LL val[100005];//每个节点及其下所有子节点的价值成绩LL treeValue[100005];//每个树的价值LL ans=0,ans1=0;vector<int> son[100005];//每个节点的儿子int low[100005];/*节点是否为根节点,根节点会乘所有点的逆元,因为乘与所有点的逆元后想要得到的是0,但是为1,所有特殊判断*/bool root[100005];int clock=0;LL dfs(int rt,int fa){ int lowu=pre[rt]=++clock;//dfs序 1开始 tree[rt]=treeNumber; LL an=weight[rt]; for(int i=0;i<G[rt].size();i++) { int x=G[rt][i]; if(!pre[x]) { int lowv=dfs(x,rt); lowu=min(lowu,lowv); son[rt].push_back(x);//存储子节点 an=(an*val[x])%inf; } else if(pre[x]<pre[rt]&&x!=fa) { lowu=min(lowu,pre[x]); } } val[rt]=an;//存储val值 return low[rt]=lowu;}LL inv(LL aaaa);//求逆元LL pow_m(LL x,LL nnn);int main(){ int T; RI(T); while(T--) { RII(n,m); for(int i=1;i<=n;i++) RI(weight[i]); clock=0; memset(pre,0,sizeof(pre)); memset(root,0,sizeof(root)); for(int i=0;i<m;i++) { int u,v; RII(u,v); G[u].push_back(v); G[v].push_back(u); } treeNumber=1; for(int i=1;i<=n;i++) { if(!pre[i]) { dfs(i,0); treeValue[treeNumber]=val[i]; root[i]=true;//i为跟 treeNumber++;//树的个数 } } LL sum=0; for(int i=0;i<treeNumber;i++) sum=sum+treeValue[i]; ans=0; for(int i=1;i<=n;i++) { LL ans2=0;//变成连通块的子节点价值和 ans1=treeValue[tree[i]];//除去ans2和i的价值和 ans1=ans1*inv(weight[i])%inf; LL ss=sum-treeValue[tree[i]];//其余树的价值 for(int j=0;j<son[i].size();j++) { int v=son[i][j]; if(low[v]>=pre[i]) { ans1=ans1*inv(val[v])%inf; ans2=ans2+val[v]; } } if(root[i]) ans1=ans1-1;//根节点要减1 ans=(ans+(((ans1+ans2+ss)%inf)*i)%inf)%inf; } printf("%I64d\n",ans); for(int i=0;i<=n;i++) { G[i].clear(); son[i].clear(); } } return 0;}LL pow_m(LL x,LL nnn){ LL res=1; while(nnn>0){ if(nnn&1) res=(res*x)%inf; x=((x%inf)*(x%inf))%inf; nnn>>=1; } return res;}LL inv(LL aaaa){ return pow_m(aaaa,inf-2);}
0 0
- hdu 5739 Fantasia
- HDU 5739 Fantasia(tarjan)
- HDU 5739 Fantasia
- HDU 5739 Fantasia 2016多校
- hdu 5739 Fantasia(Tarjan,割点)
- Hdu-5739 Fantasia (图论点双连通分量+DP)
- hdu 5739 Fantasia (2016多校第二场1006)
- 【HDU 5739】Fantasia(点双连通+dfs)
- HDU 5739 Fantasia(点双连通分量+树形DP)
- [HDU 5739] Fantasia (点双联通分量 + Block Forest Data Structure)
- From Mariposa to Fantasia
- Fantasia.进化观点
- 2016多校联合第二场 HDU5739 Fantasia 解题报告
- [HDU5739] Fantasia [2016 Multi-University Training Contest 2(多校联合训练2) F]
- 2016 Multi-University Training Contest 2 1006 Fantasia (hdu5739) 【割点 无向图dfs树 树形dp】
- 【HDU5739 2016 Multi-University Training Contest 2F】【cdq分治+并查集做法 or 点双连通做法】Fantasia 每点删除后联通块权值和的积
- hdu
- hdu
- C. Replace To Make Regular Bracket Sequence
- HTML5的小技巧(二)
- Android源码编译make的各类错误解决方案汇总
- Android Gradle BuildConfig的妙用
- 连续子数组的最大和
- HDU 5739 Fantasia
- table中cellspacing和cellpadding在css中如何设置
- ART世界探险(7) - 数组
- poj1416 Shredding Company
- none_of 源码剖析
- 广播数据
- 漫步微积分十三——高阶导数
- 来淄博旅游
- 【HDU】-4006-The kth great number(优先队列,好)