题意
台服务器构成一棵树,给定
对无法通信的服务器对,求最少有多少台服务器出现故障。
思路
贪心比较明显,先考虑一个贪心的顺序。先处理出每个服务器对的 ,假设比某对服务器 更深的服务器都已经断过了,那我们肯定要尽量往高的断,而且也只有 从深到浅的断才能保证决策清晰。由此得出算法:先对 由深到浅排序,每次都把 弄断,并把以这个 为根的子树中节点标记。服务器对中的某个点已经被标记过了,那么这次操作可以跳过(因为标记它的 肯定比现在的深,就说明这个点在半路上就已经断掉了)。而标记可以使用 序,再用树状数组区间改单点查。但何必呢?一个点被标记说明它的子树一定全被标记了,那就直接用 标记,发现某个点已被标记直接返回即可。复杂度和 个操作的复杂度是相加的,比树状数组不增反减。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define lowbit(x) ((x)&-(x))
#define N 10003
typedef long long LL;
using namespace std;
int bin[N],ans;
template<const int maxn,const int maxm>struct Linked_list
{
int head[maxn],to[maxm],nxt[maxm],tot;
void clear(){memset(head,-1,sizeof(head));tot=0;}
void add(int u,int v){to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
struct data
{
int a,b,lca,lcaLV;
bool operator <(const data &_)const{return lcaLV>_.lcaLV;}
};
struct Tree
{
int lv[N],fa[N][20],mark[N],n;
data D[N*5];
Linked_list<N,N<<1>G;
void reset(int _){n=_;G.clear();memset(mark,0,sizeof(mark));memset(fa,-1,sizeof(fa));}
void add(int u,int v){G.add(u,v);G.add(v,u);}
void dfs(int u,int d)
{
lv[u]=d;
EOR(i,G,u)
{
int v=G.to[i];
if(v!=fa[u][0])
{
fa[v][0]=u;
dfs(v,d+1);
}
}
}
void redfs(int u)
{
if(mark[u])return;
mark[u]=1;
EOR(i,G,u)
{
int v=G.to[i];
if(v!=fa[u][0])redfs(v);
}
}
void make_fa()
{
FOR(j,1,19)
FOR(i,1,n)
if(~fa[i][j-1])
fa[i][j]=fa[fa[i][j-1]][j-1];
}
void jmp(int &x,int stp)
{
while(stp)
{
x=fa[x][bin[lowbit(stp)]];
stp^=lowbit(stp);
}
}
int LCA(int a,int b)
{
if(lv[a]>lv[b])jmp(a,lv[a]-lv[b]);
else if(lv[b]>lv[a])jmp(b,lv[b]-lv[a]);
if(a==b)return a;
DOR(i,19,0)
if(fa[a][i]!=fa[b][i])
{
a=fa[a][i];
b=fa[b][i];
}
return fa[a][0];
}
void Read_data(int Q)
{
FOR(i,1,Q)
{
scanf("%d%d",&D[i].a,&D[i].b);
D[i].a++,D[i].b++;
D[i].lcaLV=lv[D[i].lca=LCA(D[i].a,D[i].b)];
}
sort(D+1,D+1+Q);
}
void destro(int k)
{
if(mark[D[k].a]||mark[D[k].b])return;
redfs(D[k].lca);
ans++;
}
}T;
int main()
{
FOR(i,2,N-3)bin[i]=bin[i>>1]+1;
int n,m;
while(~scanf("%d",&n))
{
n++;
ans=0;
T.reset(n);
FOR(i,1,n-1)
{
int u,v;
scanf("%d%d",&u,&v);
T.add(u+1,v+1);
}
T.dfs(1,0);
T.make_fa();
scanf("%d",&m);
T.Read_data(m);
FOR(i,1,m)T.destro(i);
printf("%d\n",ans);
}
return 0;
}