• Codeforces Round #613 Div.1 D.Kingdom and its Cities 贪心+虚树


    题目链接:http://codeforces.com/contest/613/problem/D

    题意概述:

      给出一棵树,每次询问一些点,计算最少删除几个点可以让询问的点两两不连通,无解输出-1。保证询问的点总数不大于300000。

    分析:

            先考虑遍历的做法,统计每个点代表的子树中联通询问点的数量。

            这个点不是询问点:如果有至少两个不同的子树中有询问点那么当前点一定被删除,因为这个时候不删除之后这两个点就是联通的;同时除了在更深的地方遇见第一种情况之外没有必要删除那些点;没有点不用管,只有一个点返回1。

      这个点是询问点:每有一颗子树中有儿子就删除掉一个点。

      判断无解:树上两个相邻的点都是询问点。

      然后建立虚树在上面跑这个算法就可以了,减少无谓遍历的点的数量。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 #include<vector>
     11 #include<cctype>
     12 using namespace std;
     13 const int maxn=300005;
     14 
     15 int N,Q;
     16 struct edge{ int to,next; }E[maxn<<1];
     17 int first[maxn],np,fa[maxn][21],dep[maxn],s[maxn],s_top;
     18 int dfn[maxn],dfs_clock,stk[maxn],top,use[maxn],u_top;
     19 bool inq[maxn];
     20 struct vTree{
     21     static const int maxnode=300005;
     22     int first[maxnode],np,ans; bool vis[maxnode];
     23     edge E[maxnode<<1];
     24     vTree(){
     25         memset(first,0,sizeof(first));
     26         np=ans=0;
     27         memset(vis,0,sizeof(vis));
     28     }
     29     void add_edge(int u,int v){
     30         E[++np]=(edge){v,first[u]};
     31         first[u]=np;
     32     }
     33     int DFS(int i,int f){
     34         int cnt=0;
     35         for(int p=first[i];p;p=E[p].next){
     36             int j=E[p].to;
     37             if(j==f) continue;
     38             if(DFS(j,i)){
     39                 if(vis[i]) ans++;
     40                 else cnt++;
     41             }
     42         }
     43         if(vis[i]) return 1;
     44         if(cnt>1){ ans++; return 0; }
     45         return cnt;
     46     }
     47 }vt;
     48 
     49 void _scanf(int &x)
     50 {
     51     x=0;
     52     char ch=getchar();
     53     while(ch<'0'||ch>'9') ch=getchar();
     54     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
     55 }
     56 int out_cnt; char out[15];
     57 void _printf(int x)
     58 {
     59     if(x<0) putchar('-'),x=-x;
     60     out[++out_cnt]=x%10+'0',x/=10;
     61     while(x) out[++out_cnt]=x%10+'0',x/=10;
     62     while(out_cnt) putchar(out[out_cnt--]);
     63     putchar('
    ');
     64 }
     65 void add_edge(int u,int v)
     66 {
     67     E[++np]=(edge){v,first[u]};
     68     first[u]=np;
     69 }
     70 void data_in()
     71 {
     72     _scanf(N);
     73     int x,y;
     74     for(int i=1;i<N;i++){
     75         _scanf(x);_scanf(y);
     76         add_edge(x,y); add_edge(y,x);
     77     }
     78     _scanf(Q);
     79 }
     80 void ready(int i,int f,int d)
     81 {
     82     fa[i][0]=f,dep[i]=d,dfn[i]=++dfs_clock;
     83     for(int j=1;(1<<j)<d;j++)
     84         fa[i][j]=fa[fa[i][j-1]][j-1];
     85     for(int p=first[i];p;p=E[p].next){
     86         if(E[p].to==f) continue;
     87         ready(E[p].to,i,d+1);
     88     }
     89 }
     90 int LCA(int x,int y)
     91 {
     92     if(dep[x]<dep[y]) swap(x,y);
     93     int len=dep[x]-dep[y];
     94     for(int i=0;(1<<i)<=len;i++)
     95         if((1<<i)&len) x=fa[x][i];
     96     if(x==y) return x;
     97     for(int i=18;i>=0;i--)
     98         if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
     99     return fa[x][0];
    100 }
    101 bool cmp(int x,int y) { return dfn[x]<dfn[y]; }
    102 void build_vt()
    103 {
    104     stk[++top]=1,inq[1]=1,use[++u_top]=1;
    105     if(s[1]!=1) stk[++top]=s[1],inq[s[1]]=1,use[++u_top]=s[1];
    106     for(int j=2;j<=s_top;j++){
    107         int z=LCA(s[j],s[j-1]);
    108         while(top>1&&dep[stk[top-1]]>dep[z]){
    109             vt.add_edge(stk[top-1],stk[top]);
    110             vt.add_edge(stk[top],stk[top-1]);
    111             top--;
    112         }
    113         if(top&&dep[stk[top]]>dep[z]){
    114             vt.add_edge(stk[top],z);
    115             vt.add_edge(z,stk[top]);
    116             top--;
    117         }
    118         if(!inq[z]) inq[z]=1,stk[++top]=z,use[++u_top]=z;
    119         if(!inq[s[j]]) inq[s[j]]=1,stk[++top]=s[j],use[++u_top]=s[j];
    120     }
    121     while(top>1){
    122         vt.add_edge(stk[top-1],stk[top]);
    123         vt.add_edge(stk[top],stk[top-1]);
    124         top--;
    125     }
    126     top=0;
    127 }
    128 void work()
    129 {
    130     ready(1,0,1);
    131     int k,x;
    132     for(int i=1;i<=Q;i++){
    133         _scanf(k);
    134         for(int j=1;j<=k;j++){
    135             _scanf(x);
    136             s[++s_top]=x,vt.vis[x]=1;
    137         }
    138         bool ok=1;
    139         for(int j=1;j<=s_top;j++)
    140             if(vt.vis[fa[s[j]][0]]){ ok=0; break; }
    141         if(!ok) _printf(-1);
    142         else{
    143             sort(s+1,s+s_top+1,cmp);
    144             build_vt();
    145             vt.DFS(1,0);
    146             _printf(vt.ans);
    147         }
    148         while(s_top) vt.vis[s[s_top--]]=0;
    149         while(u_top) inq[use[u_top]]=0,vt.first[use[u_top]]=0,u_top--;
    150         vt.np=vt.ans=0;
    151     }
    152 }
    153 int main()
    154 {
    155     data_in();
    156     work();
    157     return 0;
    158 }
    View Code
  • 相关阅读:
    CodeSmith注册错误的解决方法
    我是“坚守者”还是"背叛者"?
    拿什么留住你,我的程序员
    去除HTML代码得函数
    页面之间传递参数得几种方法
    nhibernate source code analyzed (abstract classes in nhibernate2.0)
    Web 2.0时代RSS的.Net实现
    Visual Studio.net 2003安装提示重启问题
    开放思路,综合考虑,心胸开阔,做一个合格的项目经理
    了解实际开发中 Hashtable 的特性原理 .NET, JAVA, PHP
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8763262.html
Copyright © 2020-2023  润新知