题目链接:http://codeforces.com/contest/613/problem/D

题意概述:

  给出一棵树,每次询问一些点,计算最少删除几个点可以让询问的点两两不连通,无解输出-1。保证询问的点总数不大于300000。

分析:

先考虑遍历的做法,统计每个点代表的子树中联通询问点的数量。

这个点不是询问点:如果有至少两个不同的子树中有询问点那么当前点一定被删除,因为这个时候不删除之后这两个点就是联通的;同时除了在更深的地方遇见第一种情况之外没有必要删除那些点;没有点不用管,只有一个点返回1。

  这个点是询问点:每有一颗子树中有儿子就删除掉一个点。

  判断无解:树上两个相邻的点都是询问点。

  然后建立虚树在上面跑这个算法就可以了,减少无谓遍历的点的数量。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int maxn=; int N,Q;
struct edge{ int to,next; }E[maxn<<];
int first[maxn],np,fa[maxn][],dep[maxn],s[maxn],s_top;
int dfn[maxn],dfs_clock,stk[maxn],top,use[maxn],u_top;
bool inq[maxn];
struct vTree{
static const int maxnode=;
int first[maxnode],np,ans; bool vis[maxnode];
edge E[maxnode<<];
vTree(){
memset(first,,sizeof(first));
np=ans=;
memset(vis,,sizeof(vis));
}
void add_edge(int u,int v){
E[++np]=(edge){v,first[u]};
first[u]=np;
}
int DFS(int i,int f){
int cnt=;
for(int p=first[i];p;p=E[p].next){
int j=E[p].to;
if(j==f) continue;
if(DFS(j,i)){
if(vis[i]) ans++;
else cnt++;
}
}
if(vis[i]) return ;
if(cnt>){ ans++; return ; }
return cnt;
}
}vt; void _scanf(int &x)
{
x=;
char ch=getchar();
while(ch<''||ch>'') ch=getchar();
while(ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
}
int out_cnt; char out[];
void _printf(int x)
{
if(x<) putchar('-'),x=-x;
out[++out_cnt]=x%+'',x/=;
while(x) out[++out_cnt]=x%+'',x/=;
while(out_cnt) putchar(out[out_cnt--]);
putchar('\n');
}
void add_edge(int u,int v)
{
E[++np]=(edge){v,first[u]};
first[u]=np;
}
void data_in()
{
_scanf(N);
int x,y;
for(int i=;i<N;i++){
_scanf(x);_scanf(y);
add_edge(x,y); add_edge(y,x);
}
_scanf(Q);
}
void ready(int i,int f,int d)
{
fa[i][]=f,dep[i]=d,dfn[i]=++dfs_clock;
for(int j=;(<<j)<d;j++)
fa[i][j]=fa[fa[i][j-]][j-];
for(int p=first[i];p;p=E[p].next){
if(E[p].to==f) continue;
ready(E[p].to,i,d+);
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
int len=dep[x]-dep[y];
for(int i=;(<<i)<=len;i++)
if((<<i)&len) x=fa[x][i];
if(x==y) return x;
for(int i=;i>=;i--)
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][];
}
bool cmp(int x,int y) { return dfn[x]<dfn[y]; }
void build_vt()
{
stk[++top]=,inq[]=,use[++u_top]=;
if(s[]!=) stk[++top]=s[],inq[s[]]=,use[++u_top]=s[];
for(int j=;j<=s_top;j++){
int z=LCA(s[j],s[j-]);
while(top>&&dep[stk[top-]]>dep[z]){
vt.add_edge(stk[top-],stk[top]);
vt.add_edge(stk[top],stk[top-]);
top--;
}
if(top&&dep[stk[top]]>dep[z]){
vt.add_edge(stk[top],z);
vt.add_edge(z,stk[top]);
top--;
}
if(!inq[z]) inq[z]=,stk[++top]=z,use[++u_top]=z;
if(!inq[s[j]]) inq[s[j]]=,stk[++top]=s[j],use[++u_top]=s[j];
}
while(top>){
vt.add_edge(stk[top-],stk[top]);
vt.add_edge(stk[top],stk[top-]);
top--;
}
top=;
}
void work()
{
ready(,,);
int k,x;
for(int i=;i<=Q;i++){
_scanf(k);
for(int j=;j<=k;j++){
_scanf(x);
s[++s_top]=x,vt.vis[x]=;
}
bool ok=;
for(int j=;j<=s_top;j++)
if(vt.vis[fa[s[j]][]]){ ok=; break; }
if(!ok) _printf(-);
else{
sort(s+,s+s_top+,cmp);
build_vt();
vt.DFS(,);
_printf(vt.ans);
}
while(s_top) vt.vis[s[s_top--]]=;
while(u_top) inq[use[u_top]]=,vt.first[use[u_top]]=,u_top--;
vt.np=vt.ans=;
}
}
int main()
{
data_in();
work();
return ;
}

Codeforces Round #613 Div.1 D.Kingdom and its Cities 贪心+虚树的更多相关文章

  1. 【CF613D】Kingdom and its Cities(虚树,动态规划)

    [CF613D]Kingdom and its Cities(虚树,动态规划) 题面 洛谷 CF 翻译洛谷上有啦 题解 每次构建虚树,首先特判无解,也就是关键点中存在父子关系. 考虑\(dp\),设\ ...

  2. Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset (0/1-Trie树)

    Vasiliy's Multiset 题目链接: http://codeforces.com/contest/706/problem/D Description Author has gone out ...

  3. Codeforces Round #538 (Div. 2) F 欧拉函数 + 区间修改线段树

    https://codeforces.com/contest/1114/problem/F 欧拉函数 + 区间更新线段树 题意 对一个序列(n<=4e5,a[i]<=300)两种操作: 1 ...

  4. CodeForces - 613D:Kingdom and its Cities(虚树+DP)

    Meanwhile, the kingdom of K is getting ready for the marriage of the King's daughter. However, in or ...

  5. Codeforces Round #613 (Div. 2) A-E简要题解

    contest链接:https://codeforces.com/contest/1285 A. Mezo Playing Zoma 签到 #include<iostream> #incl ...

  6. Codeforces Round #613 (Div. 2) (A-E)

    A略 直接求和最大的子序列即可(注意不能全部选中整个子序列) or #include<bits/stdc++.h> using namespace std; void solve(){ i ...

  7. Codeforces Round #613 (Div. 2)D(贪心,分治)

    构造两颗深度为30的字典树(根节点分别是0和1),结点只有0和1,从根节点向下DFS,贪心取答案. #define HAVE_STRUCT_TIMESPEC #include<bits/stdc ...

  8. Codeforces Round #613 (Div. 2) C. Fadi and LCM(LCM & GCD)

    题意: LCM(a, b) = X,求 max(a, b) 的最小值. 思路: a, b 只可能存在于 X 的因子中,枚举即可. #include <bits/stdc++.h> usin ...

  9. Codeforces Round #613 (Div. 2) B. Just Eat It!(前缀和)

    题意: 一个长为n的序列,是否存在与原序列不同的连续子序列,其元素之和大于等于原序列. 思路: 从前.后分别累加,若出现非正和,除此累加序列外的子序列元素之和一定大于等于原序列. #include & ...

随机推荐

  1. oracle10g学习笔记

    1.简介 1.1.sql:Structured Query Language 结构化查询语言 1.2.windows在目录路径中使用反斜线\,unix和linux使用正斜线/ 1.3.Number(a ...

  2. C++练习 | 掷骰子走到第n步的方法数(DFS)

    玩家根据骰子的点数决定步数,骰子点数为1的时候走一步,以此类推.求玩家走到第n步总共有多少种投骰子的方法.输入为一个整数n,输出为投骰子的方法数. #include <iostream> ...

  3. 浅谈fastDFS服务器

    FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.FastDFS特别适合以文件为载体的 ...

  4. JavaScript日期格式转换

    //日期格式转换 function dateFormat(val) {//val需要转换的日期 var fmt = "yyyy-MM-dd";//日期格式 val = val.re ...

  5. MongoDB的入门

    MongoDB mongodb是非关系型数据库 对于关系型数据库,存储数据的时候需要提前建表建库,随着数据的复杂度越来越高,所建的表的数量也越来越多:但是非关系型却不需要 mongodb的基本的命令的 ...

  6. Go语言反射之反射调用

    ## 1 概述利用反射,不仅可以获取信息,还可以创建实例,执行函数和方法.就是反射代理执行. <!-- more -->## 2 创建实例创建实例的前提是具有 `reflect.Type` ...

  7. R语言学习笔记—决策树分类

    一.简介 决策树分类算法(decision tree)通过树状结构对具有某特征属性的样本进行分类.其典型算法包括ID3算法.C4.5算法.C5.0算法.CART算法等.每一个决策树包括根节点(root ...

  8. PAT (Advanced Level) Practice 1003 Emergency

    思路:用深搜遍历出所有可达路径,每找到一条新路径时,对最大救援人数和最短路径数进行更新. #include<iostream> #include<cstdio> #includ ...

  9. leetcode记录-组合两个表

    表1: Person +-------------+---------+ | 列名 | 类型 | +-------------+---------+ | PersonId | int | | Firs ...

  10. Linux入门第五天——shell脚本入门(上)基本概念

    一.什么是shell脚本 Shell 脚本(shell script),是一种为 shell 编写的脚本程序. 二.shell入门 1.先导知识 变量知识补充:https://www.cnblogs. ...