CF613D Kingdom and its Cities 虚树

传送门



$\sum k \leq 100000$虚树套路题

设$f_{i,0/1}$表示处理完$i$以及其所在子树的问题,且处理完后$i$点存在$0/1$个没有被封住的关键点时的最小代价,转移考虑$i$是否是关键点,随便转就行了

  1 #include<bits/stdc++.h>
  2 //This code is written by Itst
  3 using namespace std;
  4
  5 inline int read(){
  6     int a = 0;
  7     bool f = 0;
  8     char c = getchar();
  9     while(c != EOF && !isdigit(c)){
 10         if(c == ‘-‘)
 11             f = 1;
 12         c = getchar();
 13     }
 14     while(c != EOF && isdigit(c)){
 15         a = (a << 3) + (a << 1) + (c ^ ‘0‘);
 16         c = getchar();
 17     }
 18     return f ? -a : a;
 19 }
 20
 21 const int MAXN = 100010;
 22 struct Edge{
 23     int end , upEd;
 24 }Ed[MAXN << 1] , newEd[MAXN];
 25 int head[MAXN] , jump[MAXN][20] , newHead[MAXN] , s[MAXN] , dfn[MAXN] , num[MAXN] , dp[MAXN][2] , dep[MAXN];
 26 int N , headS , cntEd , cntNewEd , ts , cnt;
 27 bool imp[MAXN];
 28
 29 inline void addEd(Edge* Ed , int* head , int& cntEd , int a , int b){
 30     Ed[++cntEd].end = b;
 31     Ed[cntEd].upEd = head[a];
 32     head[a] = cntEd;
 33 }
 34
 35 void init(int now , int fa){
 36     dfn[now] = ++ts;
 37     dep[now] = dep[fa] + 1;
 38     jump[now][0] = fa;
 39     for(int i = 1 ; jump[now][i - 1] ; ++i)
 40         jump[now][i] = jump[jump[now][i - 1]][i - 1];
 41     for(int i = head[now] ; i ; i = Ed[i].upEd)
 42         if(Ed[i].end != fa)
 43             init(Ed[i].end , now);
 44 }
 45
 46 inline int jumpToLCA(int x , int y){
 47     if(dep[x] < dep[y])
 48         swap(x , y);
 49     for(int i = 19 ; i >= 0 ; --i)
 50         if(dep[x] - (1 << i) >= dep[y])
 51             x = jump[x][i];
 52     if(x == y)
 53         return x;
 54     for(int i = 19 ; i >= 0 ; --i)
 55         if(jump[x][i] != jump[y][i]){
 56             x = jump[x][i];
 57             y = jump[y][i];
 58         }
 59     return jump[x][0];
 60 }
 61
 62 inline void create(){
 63     imp[1] = 0;
 64     dp[1][0] = dp[1][1] = 0;
 65     for(int i = 1 ; i <= cnt ; ++i){
 66         imp[num[i]] = 1;
 67         dp[num[i]][1] = 0;
 68         dp[num[i]][0] = N + 1;
 69     }
 70     for(int i = 1 ; i <= cnt ; ++i)
 71         if(!headS)
 72             s[++headS] = num[i];
 73         else{
 74             int t = jumpToLCA(s[headS] , num[i]);
 75             if(t != s[headS]){
 76                 while(dep[s[headS - 1]] > dep[t]){
 77                     addEd(newEd , newHead , cntNewEd , s[headS - 1] , s[headS]);
 78                     --headS;
 79                 }
 80                 addEd(newEd , newHead , cntNewEd , t , s[headS]);
 81                 if(s[--headS] != t)
 82                     s[++headS] = t;
 83             }
 84             s[++headS] = num[i];
 85         }
 86     while(headS - 1){
 87         addEd(newEd , newHead , cntNewEd , s[headS - 1] , s[headS]);
 88         --headS;
 89     }
 90     if(s[headS] != 1)
 91         addEd(newEd , newHead , cntNewEd , 1 , s[headS]);
 92     --headS;
 93 }
 94
 95 void dfs(int now){
 96     int sum = 0;
 97     for(int i = newHead[now] ; i ; i = newEd[i].upEd){
 98         int t = newEd[i].end;
 99         dfs(t);
100         if(imp[now])
101             if(jump[t][0] == now)
102                 dp[now][1] += dp[t][0];
103             else
104                 dp[now][1] += min(dp[t][0] , dp[t][1] + 1);
105         else{
106             if(jump[t][0] == now)
107                 dp[now][1] = min(sum + dp[t][1] , dp[now][1] + dp[t][0]);
108             else
109                 dp[now][1] = min(sum + dp[t][1] , dp[now][1] + min(dp[t][0] , dp[t][1] + 1));
110             if(jump[t][0] == now)
111                 sum += dp[t][0];
112             else
113                 sum += min(dp[t][0] , dp[t][1] + 1);
114         }
115         if(dp[now][1] > N)
116             dp[now][1] = N + 1;
117         if(sum > N + 1)
118             sum = N + 1;
119     }
120     sum = 0;
121     for(int i = newHead[now] ; i ; i = newEd[i].upEd){
122         int t = newEd[i].end;
123         if(!imp[now]){
124             sum += min(dp[t][0] , dp[t][1]);
125             dp[now][0] += dp[t][0];
126         }
127         dp[t][0] = dp[t][1] = imp[t] = 0;
128     }
129     if(!imp[now])
130         dp[now][0] = min(dp[now][0] , sum + 1);
131     newHead[now] = 0;
132 }
133
134 bool cmp(int a , int b){
135     return dfn[a] < dfn[b];
136 }
137
138 int main(){
139 #ifndef ONLINE_JUDGE
140     freopen("613D.in" , "r" , stdin);
141     //freopen("613D.out" , "w" , stdout);
142 #endif
143     N = read();
144     for(int i = 1 ; i < N ; ++i){
145         int a = read() , b = read();
146         addEd(Ed , head , cntEd , a , b);
147         addEd(Ed , head , cntEd , b , a);
148     }
149     init(1 , 0);
150     for(int M = read() ; M ; --M){
151         cnt = read();
152         for(int i = 1 ; i <= cnt ; ++i)
153             num[i] = read();
154         sort(num + 1 , num + cnt + 1 , cmp);
155         create();
156         dfs(1);
157         int t = min(dp[1][0] , dp[1][1]);
158         printf("%d\n" , t == N + 1 ? -1 : t);
159     }
160     return 0;
161 }

原文地址:https://www.cnblogs.com/Itst/p/10080959.html

时间: 2024-10-10 01:53:56

CF613D Kingdom and its Cities 虚树的相关文章

CF613D Kingdom and its Cities

题目链接 问题分析 首先看数据范围不难发现是虚树. 但是这个DP怎么写的我这么难受-- 应该是不难的DP,\(F[i][0]\)表示\(i\)不占领,\(F[i][1]\)表示\(i\)占领,然后分类讨论--具体的见代码吧-- 参考程序 #include <bits/stdc++.h> using namespace std; const int Maxn = 100010; const int INF = 1000010; const int MaxLog = 20; struct edge

【模板】虚树

核心思想: (听名字高大上,实际上没什么东西……虚树的题主要难在如何操作虚树) 给出$k$个关键点,我们要建出一棵只包含这些关键点和他们$lca$的点数最少的树,以实现$dp$等操作. 标志性的数据范围是$\sum{k}\leq 10^{5}$之类的. 建树方法: 1.将所有关键点按$dfs$序排序. 2.开一个栈表示根到当前点的虚树路径,并把根丢进去. 3.对于每一个关键点$u$: 若栈中只有根这一个元素,则把$u$丢进去. 否则,我们需要弹出栈中所有不在根到$u$路径上的点. 我们用$lca

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 order not to lose face in front of the relatives, the King should first finish reforms in his kingdom. As the King can not wait for his daughter's marri

Kingdom and its Cities - CF613D

Meanwhile, the kingdom of K is getting ready for the marriage of the King's daughter. However, in order not to lose face in front of the relatives, the King should first finish reforms in his kingdom. As the King can not wait for his daughter's marri

题解 CF613D 【Kingdom and its Cities】

考虑树形\(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\)本身. 不合法的情况特判掉. 考虑到多次询问和树上点集的

【CF613D】Kingdom and its Cities

题目 题目链接:https://codeforces.com/problemset/problem/613/D 一个王国有 \(n\) 座城市,城市之间由 \(n-1\) 条道路相连,形成一个树结构,国王决定将一些城市设为重要城市. 这个国家有的时候会遭受外敌入侵,重要城市由于加强了防护,一定不会被占领.而非重要城市一旦被占领,这座城市就不能通行. 国王定了若干选择重要城市的计划,他想知道,对于每个计划,外敌至少要占领多少个非重要城市,才会导致重要城市之间两两不连通.如果外敌无论如何都不可能导致

codeforces 613D:Kingdom and its Cities

Description Meanwhile, the kingdom of K is getting ready for the marriage of the King's daughter. However, in order not to lose face in front of the relatives, the King should first finish reforms in his kingdom. As the King can not wait for his daug

虚树初探

虚树其实没什么的.. 只是因为点太多了不能全开于是只开那些需要用到的点. 一棵虚树包括要求点以及它们的lca.. 虚树的构建...(其实感觉如果会虚树的构建的话接下来就是树dp啦没什么的... 首先我们应该对整棵树dfs,求出它的dfs序列.然后对于给的点,按dfs排序.. 因为我们是按dfs序排列的,所以虚树一定是由一条条链构成的.. 扫一遍给的点,如果这个点在当前的这条链上,那加在栈顶就可以了. 如果不是的话,那就不断地退栈使的原来的那条链上面的边全部被加到边集中.. rep(i,1,n){

bzoj 2286 [Sdoi2011]消耗战(虚树+树上DP)

2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1276  Solved: 445[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸