Hdu 6203 ping ping ping dfs序+树状数组维护

ping ping ping

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 629    Accepted Submission(s): 169


Problem Description
The structure of the computer room in Northeastern University is pretty miraculous. There are  n  servers, some servers connect to the gateway whose IP address is 0 directly. All servers are connected with each other by  n  netting twines. It is said that this structure is favorable for maintaining physical problem of servers.
But because of an unexpected rainstorm, the computer room was destroyed by a terrible thunderclap!
Our maintainer Bittersweet found that many servers were not able to be visited, so he hurried to the computer room to lookup the reason. After several hours, Bittersweet realized that some net gape of servers were broken by thunderclap. However, there were too many servers to find out all the broken net gapes quickly. So he came up with an idea to assess the damaged condition roughly. Bittersweet decided to turn on some servers and ping other servers randomly, then record the unsuccessful pairs of servers.
Now he need a program to analyze the record to confirm what is the  minimum  number of servers whose net gape was destroyed by thunderclap. Can you help him to complete this work?
 

Input
There are at most 20 test cases.
In each test case, the first line is an integer  n  ( 3n104 ), denoting the number of servers. The IP address of these servers is  1n .
Then follows  n  lines, each line contains two integers  u  and  v  ( 0u,vn ), denoting that the server whose IP address is  u  is connected with the server whose IP address is  v  by netting twine initially.
After those, there is one line contains only an integer  p  ( p50000 ), denoting the number that Bittersweet uses ping.
Then follows  p  lines, each line contains two integers  U  and  V  , denoting when using server  U  to ping server  V , it returned unsuccessful.
 

Output
A single integer  x  in a line, denoting at least  x  servers whose net gape were broken.
 

Sample Input
  
  
4 1 0 4 2 2 0 3 2 2 1 3 2 1
 

Sample Output
  
  
1
 

Source


给了一棵树,又给了树上的p条路径,要求切断最少的点,使得所有路径都不连通。


首先,如果删点,肯定是删lca最优,这是显然的。

对于n个lca,从深度比较深的点向上删比较好。那么,如何维护某两条路径上是否有点被删呢?

可以用dfs序来记录dfs的顺序,将一个点删掉之后,用树状数组把这个点in和out中间的所有点都+1,查询的时候,只要查询路径的起点和终点的in是否大于0即可。

因为优先从深度深的lca删点,所以不可能有路径的起点、终点同在一个被删点的子树上的情况,也就保证了答案的正确性。


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <bitset>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
#define N 10001
using namespace std;
typedef long long ll;
typedef long double ld;
const int maxn=10005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f; 
const ld pi=acos(-1.0L);
int head[maxn],dep[maxn],in[2*maxn],out[2*maxn],a[maxn*2],d[maxn*2];
int mn[maxn*2][20],f[maxn*2],from[maxn*5],to[maxn*5],lca[maxn*5];
bool visit[maxn];
int num,dfn;

struct node{
	int id,dep;
	node(int id,int dep): id(id),dep(dep) {}
	bool operator<(const node &x) const {
		return dep<x.dep;
	}
};

int lowbit(int a) {
	return (a&(-a));
}

int getsum(int tt) {
	int sum=0;
	for (int t=tt;t;t-=lowbit(t)) 
		sum+=f[t];
	return sum;
}

void update(int tt,ll c,int n) {
	int t=tt;
	for (int t=tt;t<=n;t+=lowbit(t))
		f[t]+=c;
}

struct Edge {
	int from,to,pre;
};
Edge edge[maxn*2];

void addedge(int from,int to) {
	edge[num]=(Edge){from,to,head[from]};
	head[from]=num++;
	edge[num]=(Edge){to,from,head[to]};
	head[to]=num++;
}

void dfs(int now,int step) {
	visit[now]=1;
	a[++dfn]=now;d[dfn]=step;
	in[now]=out[now]=dfn;dep[now]=step;
	for (int i=head[now];i!=-1;i=edge[i].pre) {
		int to=edge[i].to;
		if (!visit[to]) {
			dfs(to,step+1);
			out[now]=++dfn;
			a[dfn]=now;d[dfn]=step;
		}
	}
}

void init(int n) {
	int i,j;
	for (i=1;i<=n;i++) mn[i][0]=i;
	for (j=1;(1<<j)<=n;j++) {
		for (i=1;i+(1<<j)-1<=n;i++) {
			int p=mn[i][j-1],q=mn[i+(1<<(j-1))][j-1];
			mn[i][j]=d[p]<d[q]?p:q;
		}
	}
}

int findlca(int l,int r) {
	int k=0;
	if (l>r) swap(l,r);
	while (1<<(k+1)<=(r-l+1)) k++;
	int p=mn[l][k],q=mn[r-(1<<k)+1][k];
	return d[p]<d[q]?a[p]:a[q];
}

int main() {
	int n;
	while (scanf("%d",&n)!=EOF) {
		int i,j,x,y,p;
		num=dfn=0;
		n++;
		memset(head,-1,sizeof(head));
		for (i=1;i<n;i++) {
			scanf("%d%d",&x,&y);
			addedge(x+1,y+1);
		}
		scanf("%d",&p);
		mem0(visit);
		dfs(1,1);
		init(2*n-1);
		priority_queue<node> pq;
		for (i=1;i<=p;i++) {
			scanf("%d%d",&from[i],&to[i]);
			from[i]++;to[i]++;
			lca[i]=findlca(in[from[i]],in[to[i]]);
			pq.push(node(i,dep[lca[i]]));
		}
		mem0(f);
		int ans=0;
		for (i=1;i<=p;i++) {
			int now=pq.top().id;
			pq.pop();
			if (getsum(in[from[now]])>0||getsum(in[to[now]])>0) continue; else {
				ans++;
				update(in[lca[now]],1,2*n);
				update(out[lca[now]]+1,-1,2*n);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值