hdu 5927 Auxiliary Set 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 F题(树状dp)
2016-10-24 15:19
363 查看
传送门: http://acm.hdu.edu.cn/showproblem.php?pid=5927
题目大意:
有一个树,以1为根。其中某些点为重要点。
定义“重要点集”为符合如下条件的点:(1)重要点,(2)两个重要点的最近公共祖先。
给出q次询问,每次询问给出非重要点的序号,求“重要点集”中有几个点。
题目分析:
刚拿到这题的时候的dp思路有点问题,是进行了两次dfs,这样的时间复杂度就达到了O(qn),这肯定会T了。。
后来看了题解之后明白了,首先从1点dfs一趟,确定每个点的父节点、深度、以及有几棵子树。
然后令dp[i]表示节点i有几个子树有重要点,首先初始化dp[i]为子树个数(相当于初始化每个点都是重要点),然后把“非重要点”按深度逆序排列,然后依次更新非重要点的dp[i]:如果dp[i]==0,则dp[father[i]]–;因为i点非重要,且i点的子树里也没有重要点(这里因为是深度逆序排列的,所有i点的子树里的非重要点都已经计算过了,dp[i]==0要么说明他是叶子的非重要节点,要么它的子树肯定就没有重要点),那么father[i]点就有一棵子树没有重要点。
然后再统计一遍,dp[i]>=2的非重要点就一定是两个重要点的最近公共祖先。
这里有一个会T的点,我也在这里没想好就T了一下午,就是初始化dp[i]为子树个数的时候,只需要初始化非重要点就可以了,因为重要点我们是不做统计的。所以我们只维护非重要点有几个子树有重要点。
注意看第58行代码就好了,而且我才知道memset的复杂度是O(n)的,我以为是把内存单元瞬间清0。。。
那
这一段的时间复杂度就高达了O(qm)这是不允许的。
因为题里说每个测试点内的所有m加起来不超过10万,所以总复杂度可表示为O(n+mlogm).
题目大意:
有一个树,以1为根。其中某些点为重要点。
定义“重要点集”为符合如下条件的点:(1)重要点,(2)两个重要点的最近公共祖先。
给出q次询问,每次询问给出非重要点的序号,求“重要点集”中有几个点。
题目分析:
刚拿到这题的时候的dp思路有点问题,是进行了两次dfs,这样的时间复杂度就达到了O(qn),这肯定会T了。。
后来看了题解之后明白了,首先从1点dfs一趟,确定每个点的父节点、深度、以及有几棵子树。
然后令dp[i]表示节点i有几个子树有重要点,首先初始化dp[i]为子树个数(相当于初始化每个点都是重要点),然后把“非重要点”按深度逆序排列,然后依次更新非重要点的dp[i]:如果dp[i]==0,则dp[father[i]]–;因为i点非重要,且i点的子树里也没有重要点(这里因为是深度逆序排列的,所有i点的子树里的非重要点都已经计算过了,dp[i]==0要么说明他是叶子的非重要节点,要么它的子树肯定就没有重要点),那么father[i]点就有一棵子树没有重要点。
然后再统计一遍,dp[i]>=2的非重要点就一定是两个重要点的最近公共祖先。
这里有一个会T的点,我也在这里没想好就T了一下午,就是初始化dp[i]为子树个数的时候,只需要初始化非重要点就可以了,因为重要点我们是不做统计的。所以我们只维护非重要点有几个子树有重要点。
注意看第58行代码就好了,而且我才知道memset的复杂度是O(n)的,我以为是把内存单元瞬间清0。。。
那
... while(q--) { memset(m,0,sizeof(m)) ... }
这一段的时间复杂度就高达了O(qm)这是不允许的。
因为题里说每个测试点内的所有m加起来不超过10万,所以总复杂度可表示为O(n+mlogm).
//source:2016CCPC东北地区大学生程序设计竞赛 - 重现赛 #include <bits/stdc++.h> using namespace std; typedef long long ll; int T; int n,q,u,v,mi; vector<int> g[100005]; int fa[100005]; int dp[100005]; int dp2[100005]; int m[100005]; int deep[100005]; int ans; void dfs(int u,int par,int d) { deep[u]=d; if(!fa[u]) fa[u]=par; for(int i=0;i<g[u].size();i++) { int v=g[u][i]; if(!fa[v]) { dfs(v,u,d+1); dp[u]++; } } } bool cmp(int x,int y) { return deep[y]<deep[x]; } void solve() { sort(m,m+mi,cmp); for(int i=0;i<mi;i++) { int u=m[i]; if(dp2[u]==0)//u点非重要 且u点的孩子没有重要点 dp2[fa[u]]--; } for(int i=0;i<mi;i++) { int u=m[i]; if(dp2[u]>=2) ans++; } } int main() { scanf("%d",&T); for(int t=1;t<=T;t++) { scanf("%d %d",&n,&q); memset(fa,0,sizeof(fa)); memset(dp,0,sizeof(dp)); memset(deep,0,sizeof(deep)); memset(g,0,sizeof(g)); for(int i=0;i<n-1;i++) { scanf("%d %d",&u,&v); g[u].push_back(v); g[v].push_back(u); } dfs(1,-1,0);//确定父子关系和深度 printf("Case #%d:\n",t); while(q--) { // memset(m,0,sizeof(m));这句不注释掉会T!!!T了13发!!!!!! scanf("%d",&mi); for(int i=0;i<mi;i++) scanf("%d",&m[i]); for(int i=0;i<mi;i++) dp2[m[i]]=dp[m[i]]; ans=n-mi; solve(); printf("%d\n", ans); } } }
相关文章推荐
- HDU 5927 Auxiliary Set 【DFS+树】(2016CCPC东北地区大学生程序设计竞赛)
- 【HDU5927 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 F】【dfs序 + 线段树 or 树状数组 复杂度计算】Auxiliary Set 一个点如果是好点或是两个好点的LCA就是好
- (HDU 5927)Auxiliary Set 思维题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- HDU 5927 Auxiliary Set 【DFS+树】(2016CCPC东北地区大学生程序设计竞赛)
- HDU Mr. Frog’s Problem 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- (HDU 5929)Basic Data Structure 双端队列+模拟 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- (HDU 5924)Mr. Frog’s Problem 思维水题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- (HDU 5926)Mr. Frog’s Game 水题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- HDU Basic Data Structure 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- (HDU 5922)Minimum’s Revenge 思维水题 <2016CCPC东北地区大学生程序设计竞赛 - 重现赛 >
- 【HDU5928 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 G】【计算几何 凸包思想 枚举底点做DP】Birthday Gift 给定绳长最多围住多少个点
- HDU Mr. Frog’s Game 2016CCPC东北地区大学生程序设计竞赛 - 重现赛
- HDU 5929 Basic Data Structure 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
- 【HDU5922 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 A】【水题】Minimum’s Revenge
- hdu 5926 Mr. Frog’s Game 2016CCPC东北地区大学生程序设计竞赛E题(模拟)
- 【HDU5924 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 C】【水题】Mr. Frog’s Problem
- 【HDU5925 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 D】【离散化 BFS】Coconuts 大地图少数坏点输出每个联通块的大小
- 【HDU5931 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 J】【线性规划 乱搞】Mission Possible 购买护甲和回复力和速度使得最小成本穿越D距离
- HDU 5929 Basic Data Structure 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
- 【HDU5930 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 I】【线段树 预处理加变更贡献】GCD 动态修改维护全局gcd数量