HDU 6203 ping ping ping(dfs序+LCA+树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=6203

题意:

n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连通。问无法通行的点最少有多少个。

 

思路:

贪心思维,破坏两个点的LCA是最佳的。那么怎么判断现在在(u,v)之间的路径上有没有被破坏的点呢,如果没有的话那么此时就要破坏这个lca点。一开始我们要把询问按照u和v的lca深度从大到小排序,如果某个点需要被破坏,那么它的所有子节点都可以不再需要破坏别的点了(因为它的子节点到别的子节点肯定是要经过该点的,要注意这个前提是lca是排好序的,自己脑补一下~)。

所以,用dfs序来维护子节点是最好的,记录in和out两个数组。然后用树状数组来维护。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<sstream>
  6 #include<vector>
  7 #include<stack>
  8 #include<queue>
  9 #include<cmath>
 10 #include<map>
 11 #include<set>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef pair<int,ll> pll;
 15 const int INF = 0x3f3f3f3f;
 16 const int maxn = 1e4+5;
 17 
 18 int n;
 19 int Log;
 20 int dfs_clock;
 21 int in[maxn],out[maxn];
 22 int deep[maxn];
 23 int p[maxn][100];
 24 int c[2*maxn];
 25 vector<int> G[maxn];
 26 
 27 struct node
 28 {
 29     int u,v,lca;
 30 }query[50005];
 31 
 32 void dfs(int u, int fa, int d)
 33 {
 34     in[u]=++dfs_clock;
 35     deep[u]=d;
 36     p[u][0]=fa;
 37     for(int i=0;i<G[u].size();i++)
 38     {
 39         int v=G[u][i];
 40         if(v==fa)  continue;
 41         dfs(v,u,d+1);
 42     }
 43     out[u]=++dfs_clock;
 44 }
 45 
 46 
 47 bool cmp(node a, node b)
 48 {
 49     return deep[a.lca]>deep[b.lca];
 50 }
 51 
 52 
 53 void init()
 54 {
 55     for(int j=1;j<=Log;j++)
 56         for(int i=1;i<=n;i++)
 57              p[i][j]=p[p[i][j-1]][j-1];
 58 }
 59 
 60 
 61 int LCA(int x, int y)
 62 {
 63     if(x==y)  return x;
 64     if(deep[x]<deep[y])  swap(x,y);
 65     for(int i=Log;i>=0;i--)
 66     {
 67         if(deep[p[x][i]]>=deep[y])
 68             x=p[x][i];
 69     }
 70     if(x==y)  return x;
 71     for(int i=Log;i>=0;i--)
 72     {
 73         if(p[x][i]!=p[y][i])
 74         {
 75             x=p[x][i];y=p[y][i];
 76         }
 77     }
 78     return p[x][0];
 79 }
 80 
 81 int lowbit(int x)
 82 {
 83     return x&(-x);
 84 }
 85 
 86 int sum(int x)
 87 {
 88     int ret = 0;
 89     while(x>0)
 90     {
 91         ret+=c[x];
 92         x-=lowbit(x);
 93     }
 94     return ret;
 95 }
 96 
 97 void add(int x, int d)
 98 {
 99     while(x<=2*n)
100     {
101         c[x]+=d;
102         x+=lowbit(x);
103     }
104 }
105 
106 int main()
107 {
108     //freopen("in.txt","r",stdin);
109     while(~scanf("%d",&n))
110     {
111         dfs_clock=0;
112         memset(c,0,sizeof(c));
113         memset(p,0,sizeof(p));
114         for(int i=0;i<=n+1;i++)   G[i].clear();
115         for(int i=0;i<n;i++)
116         {
117             int u,v;
118             scanf("%d%d",&u,&v);
119             u++;v++;
120             G[u].push_back(v);
121             G[v].push_back(u);
122         }
123         n++;
124         for(Log=0;(1<<Log)<=n;Log++);
125         Log--;
126 
127         dfs(1,1,1);
128         init();
129         int q;
130         scanf("%d",&q);
131         for(int i=1;i<=q;i++)
132         {
133             scanf("%d%d",&query[i].u,&query[i].v);
134             query[i].u++;query[i].v++;
135             query[i].lca=LCA(query[i].u,query[i].v);
136         }
137         sort(query+1,query+q+1,cmp);
138         int ans=0;
139         for(int i=1;i<=q;i++)
140         {
141             int u=query[i].u,v=query[i].v,lca=query[i].lca;
142             int tmp1=sum(in[u]),tmp2=sum(in[v]);
143             if(sum(in[u])+sum(in[v]))  continue;
144             else
145             {
146                 ans++;
147                 add(in[lca],1);
148                 add(out[lca],-1);
149             }
150         }
151         printf("%d\n",ans);
152     }
153     return 0;
154 }

 

转载于:https://www.cnblogs.com/zyb993963526/p/7554692.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值