HDU 5739 Fantasia 2016多校
来源:互联网 发布:mac适合的浏览器 编辑:程序博客网 时间:2024/05/29 09:08
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5739
转载声明:http://blog.csdn.net/cqu_hyx/article/details/51995638
题意:
给你一个图G,每个顶点都有权值,然后删除某个点.计算该图的权值.求权值有2步
1.如果这个图是连通的,权值就是所有点的乘积.
2.如果这个图不是连通的,把分散的图按1来算,然后∑Gi;
输出答案:
个人感想:
首先我们得有预备知识,Tarjan算法求割点.
我做这题我也不会,我是磨了2天这个算法我才回顾这道题的,当然我也参考了转载的大牛的题解.
我不太懂正解的方法,感觉好复杂..这是也是超级大牛境界啊..好了回归正题吧.
首先我们一样的会想到很朴素的算法,暴力,但是暴力是(n^2)必然超时.所以我们得用其他的方法.我们其实想想就挺容易找到突破口(虽然不会做..),如果我们删除的当前的这个点不是割顶,那么我们就可以把整个原图的整个权值Sum求了,然后除以当前不是割顶的权值,就可以得到删除该点的权值就不用重新求一遍.如果当前的顶点是割顶.那么如果我们快速的知道分散的几块图的权值,那就好办了..(可是我也没什么头绪,对模板不熟).
参考了一下参考转载文章..瞬间对模板的理解有了大幅度的提升.首先我们得理解一下搜索树的概念,这不详细说.
首先预处理整个图的权值Sum.注意原图可能是分散了几块(所以每一块我们也得预处理出当前图的val).
假设图val[i]代表以i为根的图的权值.
首先TarJan算法就是建立在搜索树之上,在遍历好搜索树的时候,通过Tarjan算法,我们很容易知道当前这个点是不是割顶
这里假设 Sum=val[1]+val[6];
假设w[i]代表i点的权值
假设 t【i】代表以i节点为根的树权值
这里要分几种情况讨论:
1.不是割顶
例如第4个点.那么我们就好求了因为除去这个点对原图并没有太大的影响. 所以
去了第4个点后的权值为:G=Sum-val[1]+val[1]/w[4] ;
2.是割顶
例如第3个点.显然去了第3个点的时候,图就分成了4块,那怎么办.
这是搜索树,我们明显可以发现把如果我们知道了3点的子树的所有权值加上,3点上部分的权值不就好了..求子树(不存在回边到3点祖先点的子树,看过tarjan都会明白的)的权值应该很容易 回溯一下就好了,然后保存在一个tmp中,假设这是 tmp=t[4]+t[8];可是上部分又怎么求?我们不是求了Sum了吗?我们明显知道了啊.
所以去了3点的图的权值就为G=Sum-val【1】+val【1】/t[3]+tmp;
《———到这里好像完事了,其实还没呢..我要提2个注意点才行..所以我才说是分几种————–》
3.独立点(参考文章的,没子节点)
例如点6,这个点又没子节点那么我们怎么求去掉这个点的权值呢,这我画出来就是让大家注意的地方呢..
因为我们知道他是根节点,而且又没子节点..那就好求咯.直接看公式。 G=Sum-val【2】;
4.根节点(参考文章的)
因为我们知道Tarjan算法对根节点是进行特殊处理的.他的重点就不言而喻.
根节点分也是分两种情况! 不是割顶. 是顶.只要我们同样的像上面两种情况一样做操作一样不会有问题.
不过根节点在求割顶的时候有个快速的计算公式
G=Sum-val[1]+tmp 并不需要除数.
通过这几步我们通过ans[i] 存在去了i点之后Gi的权值. 然后求出 Ans=∑i*ans【i】%mod 就是答案了..
我是通过手模参考文章才发现这些问题了.对TarJan算法了解更深了..莫莫莫,感觉以后这些问题也不成问题了..
分析:Tarjan求割顶算法
代码:
/* Author:GavinjouElephant * Title: * Number: * main meanning: * * * *///#define OUT#include <iostream>using namespace std;#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <sstream>#include <cctype>#include <vector>#include <set>#include <cstdlib>#include <map>#include <queue>//#include<initializer_list>//#include <windows.h>//#include <fstream>//#include <conio.h>#define MaxN 0x7fffffff#define MinN -0x7fffffff#define Clear(x) memset(x,0,sizeof(x))typedef long long ll;const int INF=0x3f3f3f3f;const ll maxn=2e5+10;const ll mod=1e9+7;ll T;ll N,M;struct Edge{ ll to; ll next;};Edge edge[5*maxn];ll head[maxn];ll tot,Index;ll LOW[maxn];ll DFN[maxn];ll ans[maxn];ll Sum;bool cut[maxn];//判断是否为割顶;ll w[maxn];//获取每个点的权值ll val[maxn];//算出子树的所有乘积,其实有用的只是根..ll top;//s根起点的计数ll s[maxn];//根起点bool vis[maxn];//dfs标记,ll root;void addedge(ll u,ll v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++;}ll qpow(ll a,ll n){ ll res=1; while(n) { if(n&1)res=(res*a)%mod; a=(a*a)%mod; n>>=1; } return res;}ll inv(ll x)//费马小定理{ return qpow(x,mod-2);}ll Tarjan(ll u,ll p)//kuangbin模板Tarjan{ ll res=w[u]; ll sum=0; ll pro=w[u]; ll v; LOW[u]=DFN[u]=++Index; ll son=0; ll pre_cnt=0; bool flag=true;//是否为孤立点. for(int j=head[u];j!=-1;j=edge[j].next) { v=edge[j].to; if(v == fa && pre_cnt ==0){pre_cnt++;continue;} if(!DFN[v]) { son++; ll tmp=Tarjan(v,u); LOW[u]=min(LOW[u],LOW[v]); if(u==fa) sum=(sum+tmp)%mod; if(u==fa &&son>1)flag=false; if(u!=fa &&LOW[v]>=DFN[u]) { cut[u]=true; flag=false; sum=(sum+tmp)%mod; pro=(pro*tmp)%mod; } res=(res*tmp)%mod; } else if(LOW[u]>DFN[v]) LOW[u]=DFN[v]; } if(flag) { if(u==fa && head[u]==-1) ans[u]=(Sum-val[root]+mod)%mod;//如果这个是孤立点,而且是父节点,直接用整个图的总权值相减就好了. else ans[u]=( (Sum-val[root]+mod)%mod +(val[root]*inv(w[u])%mod))%mod;//否则这不是割顶,那么直接去掉这个.要分块!! } else { ll pre=val[root]*inv(pro)%mod; if(u!=fa ) sum=(sum+pre)%mod; ans[u]=(Sum-val[root]+mod)%mod; ans[u]=(ans[u]+sum)%mod; } return res;}void init(){ memset(head,-1,sizeof(head)); memset(DFN,0,sizeof(DFN)); Sum=top=tot=Index=0; memset(cut,false,sizeof(cut)); memset(vis,false,sizeof(vis)); memset(ans,0,sizeof(ans));}void dfs(ll u){ vis[u]=true; val[u]=w[u]; for(int j=head[u];j!=-1;j=edge[j].next) { ll v=edge[j].to; if(!vis[v]) { dfs(v); val[u]=(val[u]*val[v])%mod; } }}int main(){#ifdef OUT freopen("coco.txt","r",stdin); freopen("lala.txt","w",stdout);#endif scanf("%I64d",&T); while(T--) { init(); ll x,y; scanf("%I64d%I64d",&N,&M); for(int i=1;i<=N;i++) { scanf("%I64d",&w[i]); } for(int i=0;i<M;i++) { scanf("%I64d%I64d",&x,&y); addedge(x,y); addedge(y,x); } for(int i=1;i<=N;i++) { if(vis[i])continue; dfs(i); s[top++]=i; Sum=(Sum+val[i])%mod; } for(int i=0;i<top;i++) { root=s[i]; Tarjan(s[i],s[i]); } ll Ans=0; for(int i=1;i<=N;i++) { Ans=(Ans+(i*ans[i])%mod)%mod; } printf("%I64d\n",Ans%mod); } return 0;}
朴素想法代码:
/* Author:GavinjouElephant * Title: * Number: * main meanning: * * * *///#define OUT#include <iostream>using namespace std;#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <sstream>#include <cctype>#include <vector>#include <set>#include <cstdlib>#include <map>#include <queue>//#include<initializer_list>//#include <windows.h>//#include <fstream>//#include <conio.h>#define MaxN 0x7fffffff#define MinN -0x7fffffff#define Clear(x) memset(x,0,sizeof(x))typedef long long ll;const int INF=0x3f3f3f3f;int T;int N;const int maxn=1e5;const int mod=1e9+7;string str;int f[maxn];int w[maxn];ll dp[maxn];int opt(int a,int b){ if(str[0]=='A') return a&b; if(str[0]=='O') return a|b; return a^b;}void init(){ memset(f,-1,sizeof(f)); memset(dp,0,sizeof(dp));}ll V(int s){ int tmp=f[s]; while(tmp!=-1) { dp[s]=max(dp[s],dp[tmp]+opt(w[s],w[tmp])); tmp=f[tmp]; //cout<<tmp<<endl; } return dp[s];}int main(){#ifdef OUT freopen("coco.txt","r",stdin); freopen("lala.txt","w",stdout);#endif scanf("%d",&T); while(T--) { init(); scanf("%d",&N); cin>>str; ll ans=0; for(int i=1;i<=N;i++) scanf("%d",&w[i]); for(int i=2;i<=N;i++) { scanf("%d",&f[i]); } for(int i=1;i<=N;i++) { ans+=(i*(w[i]+V(i)))%mod; } printf("%I64d\n",ans); } return 0;}
- HDU 5739 Fantasia 2016多校
- hdu 5739 Fantasia
- HDU 5739 Fantasia(tarjan)
- HDU 5739 Fantasia
- hdu 5739 Fantasia (2016多校第二场1006)
- hdu 5739 Fantasia(Tarjan,割点)
- Hdu-5739 Fantasia (图论点双连通分量+DP)
- 【HDU 5739】Fantasia(点双连通+dfs)
- HDU 5739 Fantasia(点双连通分量+树形DP)
- [HDU 5739] Fantasia (点双联通分量 + Block Forest Data Structure)
- 2016多校联合第二场 HDU5739 Fantasia 解题报告
- [HDU5739] Fantasia [2016 Multi-University Training Contest 2(多校联合训练2) F]
- From Mariposa to Fantasia
- Fantasia.进化观点
- 2016 Multi-University Training Contest 2 1006 Fantasia (hdu5739) 【割点 无向图dfs树 树形dp】
- 【HDU5739 2016 Multi-University Training Contest 2F】【cdq分治+并查集做法 or 点双连通做法】Fantasia 每点删除后联通块权值和的积
- hdu 5739 2016多校2
- 2016 多校 hdu 5723
- 特效1: 鼠标移动到该区域则显示小图标
- 散列表学习
- jQuery选择器
- 【Java基础】类变量(静态变量)、成员变量、局部变量的区分理解及存储分类
- mock测试
- HDU 5739 Fantasia 2016多校
- 取样问题
- Android Volley完全解析(一),初识Volley的基本用法
- vim的安装及部分问题解决方法
- malloc calloc realloc的函数原型和功能
- 使用FAAD库解码AAC实例及 及 faad解码后的通道数不正确的问题
- DAO模式
- java中遇到的对String的分割--------split(新手记录平日所遇到的,请大神海涵)
- Word Ladder II 解题总结