考虑树形\(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. Nacos学习笔记

    Nacos简介 Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现.服务配置.服务元数据及流量管理.Nacos 帮助更敏捷和容易地构建.交付和管理微服务平台. Nacos 是构建以“服 ...

  2. vueX基础知识笔记

    接着昨天的知识点 mutations提交时,有时候达不到想要的响应式,我们必须要将数据提前放到state中,否则不会达到响应式的效果.比如 state.info['address'] = value ...

  3. 表达式计算开源组件(NCalc.NetCore)

    首先,这款组件是开源的,NCalc是.net中的一个数学表达式求值程序.NCalc可以解析任何表达式并计算结果,包括静态或动态参数和自定义函数. 官网地址:http://ncalc.codeplex. ...

  4. asp.net Core依赖注入(自带的IOC容器)

    今天我们主要讲讲如何使用自带IOC容器,虽然自带的功能不是那么强大,但是胜在轻量级..而且..不用引用别的库. 在新的ASP.NET Core中,大量的采用了依赖注入的方式来编写代码. 比如,在我们的 ...

  5. JavaScript中__proto__与prototype的关系(转)

    一.所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function) 1 2 3 4 5 6 7 8 9 Number.__proto__ ...

  6. Linux文件权限学习笔记

    文件权限共10个字符,第一个字符表示该文件是[文件夹]或[文件]——如果是字符“d"则表示该文件是文件夹:如果是字符“-”则表示是文件. 后九个字符,三个一组,共三组,分别表示[所有者权限] ...

  7. Quartz.Net系列(九):Trigger之CronScheduleBuilder和Cron表达式详解

    1.使用 var scheduler =await StdSchedulerFactory.GetDefaultScheduler(); await scheduler.Start(); var jo ...

  8. VMware Workstation安装centos

    begin 2020年7月4日16:32:34 今天我们是食神,来做一道菜,名曰VMware Workstation安装centos. 首先我们需要准备好锅和食材. 锅和食材 锅:VMware Wor ...

  9. tbody滚动条占位导致与thead表头错位

    tbody出滚动条导致表头错位,上网上搜了一下,发现全是答非所问,能隐藏滚动条,还用问??我当前作出的效果是当tbody内容在正常情况下显示时,不显示滚动条,当内容区域高度超过外部容器时,滚动条自动显 ...

  10. bootstrap悬停下拉菜单显示

    使用Bootstrap导航条组件时,如果你的导航条带有下拉菜单,那么这个带下拉菜单的导航在点击时只会浮出下拉菜单,它本身的href属性会失效,也就是失去了超链接功能,这并不是我想要的,我希望导航条的链 ...