考虑树形\(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. Struts2 自定义拦截器时Action无法接收到参数

    问题:自定义拦截器,没有添加defaultStack导致Action无法接受到参数 解决办法: 方法一,添加defaultStack,然后在Action中引用 自定义的stack,其实defaultS ...

  2. Python3-threading模块-多线程

    什么是线程? 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 P ...

  3. windows操作系统查看端口,关闭端口进程

    根据端口号查找进程 netstat -ano | findstr "端口号" 杀死进程 taskkill /pid "pid(最后一个数值)" /f

  4. 客官,来看看AspNetCore的身份验证吧

    开篇 这段时间潜水了太久,终于有时间可以更新一篇文章了. 通过本篇文章您将Get: Http的一些身份验证概念 在AspNetCore中实现身份验证方案 JWT等概念的基础知识 使用Bearer To ...

  5. Vue父子之间的值传递

    将通过两个input框实现父子之间的值传递作为演示,效果图 先注册父子各一个组件,代码如下 <div id="app"> <parent></pare ...

  6. 聊聊Java中的异常及处理

    前言 在编程中异常报错是不可避免的.特别是在学习某个语言初期,看到异常报错就抓耳挠腮,常常开玩笑说编程1分钟,改bug1小时.今天就让我们来看看什么是异常和怎么合理的处理异常吧! 异常与error介绍 ...

  7. scala数据结构(一)

    一.概述 1,特点 )Scala同时支持不可变集合和可变集合 )两个主要的包: 不可变集合:scala.collection.immutable 可变集合: scala.collection.muta ...

  8. css定位方式有哪几种?

    复杂的网页布局都是通过各种网页元素灵活定位实现的,网页中的各种元素定位都有自己的特点.下面我们来看一下css的几种定位方式. float定位(即浮动定位): 这种定位方式很简单,只需规定一个浮动的方向 ...

  9. python 的迭代

    字典的迭代: #创建字典 dict={'a':1,'b':2,'c':3} #key和value的迭代 for key,value in dict.items(): print(key,':',val ...

  10. 关键字: this的使用

    1.可以调用的结构:属性.方法:构造器2.this调用属性.方法:this理解为:当前对象 或 当前正在创建的对象 2.1 在类的方法中,我们可以使用"this.属性"或" ...