题意:

一个王国有n座城市,城市之间由n-1条道路相连,形成一个树结构,国王决定将一些城市设为重要城市。

这个国家有的时候会遭受外敌入侵,重要城市由于加强了防护,一定不会被占领。而非重要城市一旦被占领,这座城市就不能通行。

国王定了若干选择重要城市的计划,他想知道,对于每个计划,外敌至少要占领多少个非重要城市,才会导致重要城市之间两两不连通。如果外敌无论如何都不可能导致这种局面,输出-1

————————————————————————————————————————

首先,在洛谷交的,有一个点没有过。CF,外语网站而且很慢,不试了!

建立虚树,然后在虚树上面树形DP。

虚树,就是在做树形DP时,我们经常发现有许多点根本没用,比如这个题目中的非重要城市。我们可以把重要节点和他们的连接点(LCA)取出来重新建一棵树,这就是虚树。

方法:

首先,dfs,求出dfs序:DFN,并求出每个点的深度dep[]和LCA辅助数组f[][]

void dfs(int u,int fa)
{
f[u][0]=fa;
for(int i=1;i<20 && f[u][i-1]!=0;++i)f[u][i]=f[f[u][i-1]][i-1];
dfn[u]=++tim;dep[u]=dep[fa]+1;
for(int i=head[u];i;i=e[i].nxt)
if(e[i].v!=fa)dfs(e[i].v,u);
}

然后,对于所有的重要节点进行记录(pt[])并打标记(ispt[])

下面,将重要节点(pt[])按照DFN[]进行排序

最后,我们将pt[]中的重要节点一次取出建立虚树。

建立的虚树采用增量的方法:

把取出的点一次加入到栈里面,从栈底到栈顶的重要节点可以连成一条从根方向到叶子方向的链。

当加入当前点u时,如果栈中没用其它的点则可以直接加入点u

如果u点与栈顶的点的lca是栈顶点,则可以直接将u点加入,这样栈中的点形成一条更长的链

如果栈顶点和u点的lca不是栈顶点,那么也就是u点和栈顶点处于原树中不同的分支。我们比lca更深(比较dep[])的点依次弹出,并把相邻的点建边(这就是虚树的一部分)。然后把判断lca是否在栈中,如果不在就需要把lca加入栈中,然后把u点加入栈中。

这样所有的点都加入完成后,最后还剩余了栈中的一条链,把栈中的点一次出栈并建边,虚树完成。

注:为了有一个总的根,所以通常把1号点加入栈中。

void insert(int x)
{
if(top==0)
{
sta[top=1]=x;
return;
}
int l=lca(x,sta[top]);
if(l==sta[top])
{
sta[++top]=x;
return;
}
while(top>1 && dep[sta[top-1]]>=dep[l])
{
addage(sta[top],sta[top-1],ee,headd,jss);
addage(sta[top-1],sta[top],ee,headd,jss);
--top;
}
if(l!=sta[top])
{
addage(sta[top],l,ee,headd,jss);
addage(l,sta[top],ee,headd,jss);
sta[top]=l;
}
sta[++top]=x;
}
void build()
{
jss=0;
memset(headd,0,sizeof headd);
if(pt[1]!=1)sta[top=1]=1;
for(int i=1;i<=m;++i)
insert(pt[i]);
while(top>1)
{
addage(sta[top],sta[top-1],ee,headd,jss);
addage(sta[top-1],sta[top],ee,headd,jss);
--top;
}
}

————————————————————————————————————————

  1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn=1e5+10;
4 int n,q;
5 struct edge
6 {
7 int u,v,nxt;
8 }e[maxn],ee[maxn];
9 int head[maxn],headd[maxn],js,jss;
10 void addage(int u,int v,edge e[],int head[],int &js)
11 {
12 e[++js].u=u;e[js].v=v;
13 e[js].nxt=head[u];head[u]=js;
14 }
15 int dfn[maxn],tim,f[maxn][20],dep[maxn];
16 void dfs(int u,int fa)
17 {
18 f[u][0]=fa;
19 for(int i=1;i<20 && f[u][i-1]!=0;++i)f[u][i]=f[f[u][i-1]][i-1];
20 dfn[u]=++tim;dep[u]=dep[fa]+1;
21 for(int i=head[u];i;i=e[i].nxt)
22 if(e[i].v!=fa)dfs(e[i].v,u);
23 }
24 int pt[maxn],m,sta[maxn],top;
25 bool ispt[maxn];
26 bool cmp(int a,int b)
27 {
28 return dfn[a]<dfn[b];
29 }
30 int lca(int u,int v)
31 {
32 if(dep[v]>dep[u])swap(u,v);
33 for(int i=19;i>=0;--i)
34 if(dep[f[u][i]]>=dep[v])u=f[u][i];
35 if(u==v)return u;
36 for(int i=19;i>=0;--i)
37 if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
38 return f[u][0];
39 }
40 void insert(int x)
41 {
42 if(top==0)
43 {
44 sta[top=1]=x;
45 return;
46 }
47 int l=lca(x,sta[top]);
48 if(l==sta[top])
49 {
50 sta[++top]=x;
51 return;
52 }
53 while(top>1 && dep[sta[top-1]]>=dep[l])
54 {
55 addage(sta[top],sta[top-1],ee,headd,jss);
56 addage(sta[top-1],sta[top],ee,headd,jss);
57 --top;
58 }
59 if(l!=sta[top])
60 {
61 addage(sta[top],l,ee,headd,jss);
62 addage(l,sta[top],ee,headd,jss);
63 sta[top]=l;
64 }
65 sta[++top]=x;
66 }
67 void build()
68 {
69 jss=0;
70 memset(headd,0,sizeof headd);
71 if(pt[1]!=1)sta[top=1]=1;
72 for(int i=1;i<=m;++i)
73 insert(pt[i]);
74 while(top>1)
75 {
76 addage(sta[top],sta[top-1],ee,headd,jss);
77 addage(sta[top-1],sta[top],ee,headd,jss);
78 --top;
79 }
80 }
81 int ff[maxn],g[maxn];
82 void dp(int u,int fa)
83 {
84 ff[u]=g[u]=0;
85 for(int i=head[u];i;i=e[i].nxt)
86 {
87 int v=e[i].v;
88 if(v==fa)continue;
89 dp(v,u);
90 ff[u]+=ff[v];g[u]+=g[v];
91 }
92 if(!ispt[u])
93 {
94 ff[u]+=(g[u]>1);
95 g[u]=(g[u]==1);
96 }
97 else
98 {
99 ff[u]+=g[u];
100 g[u]=1;
101 }
102 }
103 int main()
104 {
105 scanf("%d",&n);
106 for(int u,v,i=1;i<n;++i)
107 {
108 scanf("%d%d",&u,&v);
109 addage(u,v,e,head,js);addage(v,u,e,head,js);
110 }
111 dfs(1,0);
112 scanf("%d",&q);
113 while(q--)
114 {
115 scanf("%d",&m);
116 memset(pt,0,sizeof pt);
117 memset(ispt,0,sizeof ispt);
118 for(int i=1;i<=m;++i)
119 {
120 scanf("%d",pt+i);
121 ispt[pt[i]]=1;
122 }
123 sort(pt+1,pt+m,cmp);
124 bool flag=1;
125 for(int i=1;i<=m;++i)
126 if(ispt[f[pt[i]][0]])flag=0;
127 if(!flag)
128 {
129 puts("-1");
130 continue;
131 }
132 build();
133 dp(1,0);
134 printf("%d\n",ff[1]);
135 }
136 return 0;
137 }

CF613D的更多相关文章

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

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

  2. 【CF613D】Kingdom and its Cities

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

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

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

  4. CF613D Kingdom and its Cities 虚树

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

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

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

  6. Kingdom and its Cities - CF613D

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

  7. [CF613D]Kingdom and its Cities

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

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

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

  9. 题解 CF613D 【Kingdom and its Cities】

    考虑树形\(DP\),设\(num_x\)记录的为当\(1\)为根时,以\(x\)为子树中重要城市的个数. 那么进行分类讨论: ① 当\(num_x≠0\)时,则需将其所有满足\(num_y≠0\)的 ...

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

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

随机推荐

  1. [LeetCode]662. Maximum Width of Binary Tree判断树的宽度

    public int widthOfBinaryTree(TreeNode root) { /* 层序遍历+记录完全二叉树的坐标,左孩子2*i,右孩子2*i+1 而且要有两个变量,一个记录本层节点数, ...

  2. redo log 有什么作用?

    mysql 为了提升性能不会把每次的修改都实时同步到磁盘,而是会先存到Boffer Pool(缓冲池)里头,把这个当作缓存来用.然后使用后台线程去做缓冲池和磁盘之间的同步. 那么问题来了,如果还没来的 ...

  3. 前端JS获取用户位置

    精确至城市 (基于腾讯位置服务的IP定位,需申请KEY)

  4. gcc/g++命令参数

    在windows环境下,我们运行一程序,只需要在VS中点击运行按键即可,VS帮我们做完了程序的预处理.编译.汇编.链接阶段 但是在linux环境下,我们只能借助gcc/g++完成这一系列的操作 -o参 ...

  5. 简单4步,利用Prometheus Operator实现自定义指标监控

    本文来自Rancher Labs 在过去的文章中,我们花了相当大的篇幅来聊关于监控的话题.这是因为当你正在管理Kubernetes集群时,一切都会以极快的速度发生变化.因此有一个工具来监控集群的健康状 ...

  6. SpringBoot整合sa-token,完成网站权限验证

    sa-token是什么? sa-token是一个JavaWeb轻量级权限认证框架,其API调用非常简单,有多简单呢?以登录验证为例,你只需要: // 在登录时写入当前会话的账号id StpUtil.s ...

  7. asp.net core 5.0 中的 JsonConsole

    asp.net core 5.0 中的 JsonConsole Intro asp.net core 5.0 中日志新增了 JsonConsole,还是输出日志到 Console,但是会应用 Json ...

  8. std::thread线程库详解(2)

    目录 目录 简介 最基本的锁 std::mutex 使用 方法和属性 递归锁 std::recursive_mutex 共享锁 std::shared_mutex (C++17) 带超时的锁 总结 简 ...

  9. Hadoop伪分布式模式

    搭建在单一服务器 基于官方文档 http://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-common/SingleCluster ...

  10. Oracle 锁表以及解锁

    -- kill_exec 列为解锁的语句,copy出来执行即可.select 'alter system kill session ''' || s.sid || ',' || s.serial# | ...