考虑树形\(DP\),设\(num_x\)记录的为当\(1\)为根时,以\(x\)为子树中重要城市的个数。

那么进行分类讨论:

① 当\(num_x≠0\)时,则需将其所有满足\(num_y≠0\)的儿子\(y\)删去。

② 当\(num_x=0\)时,若满足\(num_y≠0\)的儿子\(y\)个数\(cnt=1\),则直接让\(num\)进行向上传递,若满足\(num_y≠0\)的儿子\(y\)个数\(cnt>1\),则需删去\(x\)本身。

不合法的情况特判掉。

考虑到多次询问和树上点集的特性,考虑用虚树来优化\(DP\)。

多次建虚树时记得清空\(num\),但不要用\(memset\),无法保证复杂度,应记录虚树上的点,只清零这些点。

其他实现细节就看代码吧。

\(code:\)

#include<bits/stdc++.h>
#define maxn 200010
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag) x=-x;
}
int n,q,ans,tmp_cnt;
bool flag;
int query[maxn],tmp[maxn],num[maxn];
struct edge
{
int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
e[++edge_cnt]=(edge){to,head[from]};
head[from]=edge_cnt;
}
int dfn_cnt;
int de[maxn],dfn[maxn],top_fa[maxn],fa[maxn],son[maxn],siz[maxn];
void dfs_son(int x,int fath)
{
siz[x]=1;
fa[x]=fath;
de[x]=de[fath]+1;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fath) continue;
dfs_son(y,x);
siz[x]+=siz[y];
if(siz[son[x]]<siz[y]) son[x]=y;
}
}
void dfs_chain(int x,int tp)
{
dfn[x]=++dfn_cnt,top_fa[x]=tp;
if(son[x]) dfs_chain(son[x],tp);
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(dfn[y]) continue;
dfs_chain(y,y);
}
}
int lca(int x,int y)
{
while(top_fa[x]!=top_fa[y])
{
if(de[top_fa[x]]<de[top_fa[y]]) swap(x,y);
x=fa[top_fa[x]];
}
if(dfn[x]>dfn[y]) swap(x,y);
return x;
}
bool cmp(const int &a,const int &b)
{
return dfn[a]<dfn[b];
}
int st[maxn],top;
void insert(int x)
{
if(x==1) return;
if(top==1)
{
st[++top]=x;
return;
}
int anc=lca(x,st[top]);
if(anc==st[top])
{
st[++top]=x;
return;
}
while(top>1&&dfn[anc]<=dfn[st[top-1]]) add(st[top-1],st[top]),top--,tmp[++tmp_cnt]=st[top];
if(anc!=st[top]) add(anc,st[top]),st[top]=anc,tmp[++tmp_cnt]=st[top];
st[++top]=x;
}
void dp(int x)
{
int cnt=0,sum=0;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
dp(y);
if(num[x]&&num[y]) ans++;
if(!num[x]&&num[y])
{
cnt++;
sum+=num[y];
}
}
if(!num[x])
{
if(cnt==1) num[x]+=sum;
if(cnt>1) ans++;
}
head[x]=0;
}
void clear()
{
edge_cnt=0;
memset(head,0,sizeof(head));
}
int main()
{
read(n);
for(int i=1;i<n;++i)
{
int a,b;
read(a),read(b);
add(a,b),add(b,a);
}
dfs_son(1,0);
dfs_chain(1,1);
clear();
read(q);
while(q--)
{
int k;
read(k);
edge_cnt=tmp_cnt=flag=ans=0;
for(int i=1;i<=k;++i)
{
read(query[i]);
num[query[i]]++;
}
for(int i=1;i<=k;++i)
{
if(num[fa[query[i]]])
{
puts("-1");
flag=true;
break;
}
}
if(flag)
{
for(int i=1;i<=k;++i) num[query[i]]=0;
continue;
}
sort(query+1,query+k+1,cmp);
st[top=1]=1,tmp[tmp_cnt=1]=1;
for(int i=1;i<=k;++i) insert(query[i]);
while(top) add(st[top-1],st[top]),top--,tmp[++tmp_cnt]=st[top];
dp(1);
for(int i=1;i<=tmp_cnt;++i) num[tmp[i]]=0;
for(int i=1;i<=k;++i) num[query[i]]=0;
printf("%d\n",ans);
}
return 0;
}

题解 CF613D 【Kingdom and its Cities】的更多相关文章

  1. CF613D Kingdom and its Cities 虚树 树形dp 贪心

    LINK:Kingdom and its Cities 发现是一个树上关键点问题 所以考虑虚树刚好也有标志\(\sum k\leq 100000\)即关键点总数的限制. 首先当k==1时 答案显然为0 ...

  2. CF613D Kingdom and its Cities 虚树

    传送门 $\sum k \leq 100000$虚树套路题 设$f_{i,0/1}$表示处理完$i$以及其所在子树的问题,且处理完后$i$所在子树内是否存在$1$个关键点满足它到$i$的路径上不存在任 ...

  3. CF613D:Kingdom and its Cities(树形DP,虚树)

    Description 一个王国有n座城市,城市之间由n-1条道路相连,形成一个树结构,国王决定将一些城市设为重要城市. 这个国家有的时候会遭受外敌入侵,重要城市由于加强了防护,一定不会被占领.而非重 ...

  4. [CF613D]Kingdom and its Cities

    description 题面 data range \[n, q,\sum k\le 10^5\] solution 还是虚树的练手题 \(f[0/1][u]\)表示\(u\)的子树内,\(u\)是否 ...

  5. CF613D Kingdom and its Cities 虚树 + 树形DP

    Code: #include<bits/stdc++.h> #define ll long long #define maxn 300003 #define RG register usi ...

  6. CF613D Kingdom and its Cities(虚树+贪心)

    很休闲的一个题啊 其实一看到关于\(\sum k\)的限制,就知道是个虚树的题了 首先我们把虚树建出来,然后考虑怎么计算个数呢? 我们令\(f[x]\)表示以\(x\)的子树中,剩余了多少个还没有切断 ...

  7. 【CF613D】Kingdom and its Cities 虚树+树形DP

    [CF613D]Kingdom and its Cities 题意:给你一棵树,每次询问给出k个关键点,问做多干掉多少个非关键点才能使得所有关键点两两不连通. $n,\sum k\le 10^5$ 题 ...

  8. 【CF613D】Kingdom and its Cities

    [CF613D]Kingdom and its Cities 题面 洛谷 题解 看到关键点当然是建虚树啦. 设\(f[x]\)表示以\(x\)为根的子树的答案,\(g[x]\)表示以\(x\)为根的子 ...

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

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

随机推荐

  1. 一位老程序员说,有这份python3的开发指南,月薪能突破20K

    推荐视频: AI人工智能识别技术_第一节AI人工智能识别技术_第二节Python基础案例之教你如何查询对方IP_第一节Python基础案例之教你如何查询对方IP_第二节 有程序员说,这份python3 ...

  2. 黎活明8天快速掌握android视频教程--24_网络通信之网页源码查看器

    1 该项目的主要功能就是从将后台的html网页在Android的界面上显示出来 后台就是建立一个java web工程在工程尚建立一个html或者jsp文件就可以了,这里主要看Android客户端的程序 ...

  3. Java | 内部类(Inner Class)

    前言 本文内容主要来自 Java 官方教程中的<嵌套类>章节. 本文提供的是 JDK 14 的示例代码. 定义 内部类(Inner Class),是 Java 中对类的一种定义方式,是嵌套 ...

  4. js事件入门(2)

    2.鼠标事件 鼠标事件就是用户与页面的许多交互时通过鼠标移动或者鼠标点击等触发的事件. 2.1.onmousedown 鼠标按下的时候触发的事件 <!DOCTYPE html> <h ...

  5. QtableWidget用法流程

    QtableWidget用法流程 ​ 作者:流火 日期:2020/5/10 QTableWidget的基本构造函数 QTableWidget 是QTableview的子类.主要去呗是QTableVie ...

  6. 【经验】GaussDB(for MySQL)性能优化 —— 日志的“快递驿站”

    GaussDB(for MySQL)数据库在写入性能上,在业界同类产品中是最好的,这主要得益于GaussDB(for MySQL)在MySQL内核方面的诸多优化.其中有一项从“送快递”得来灵感的优化— ...

  7. 读取模式下cbc latch的事件模拟(热块竞争和热链竞争)-P62

    文章目录 1. 背景 2. 过程 2.1 热块竞争 2.1.1 版本11.2.0.1.0 2.1.1.1 session 1(sid:34) 2.1.1.2 session 2(sid:35) 2.1 ...

  8. CenterOS的安装配置(配图解)

    CenterOS的安装配置 一.    配置虚拟机 打开Virtual Machine(虚拟机),点击create new virtual machine 进入新建虚拟机向导页面,选择[Custom( ...

  9. web前端开发_文件/目录/样式/函数等命名规范

    页面的命名规则 统一用翻译的英文命名(推荐) 统一用拼音命名(拼音的简化也可) 如果文件名过长,企业要提前约定一份缩写的规范,如pro—product 例如: 首页—index 产品列表—prolis ...

  10. HTML5 Canvas绘图基本使用方法, H5使用Canvas绘图

    Canvas 是H5的一部分,允许脚本语言动态渲染图像.Canvas 定义一个区域,可以由html属性定义该区域的宽高,javascript代码可以访问该区域,通过一整套完整的绘图功能(API),在网 ...