CF613D

题意:

一个王国有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号点加入栈中。

 

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

CF613D
  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 }
View Code

 

上一篇:线段树脑洞题 P2184 贪婪大陆


下一篇:Java实现SQLite数据库中Blob数据的读写