Time Limit: 2000/1000 MS (Java/Others) LCA + 贪心
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?


There are at most $ 20$ test cases.
In each test case, the first line is an integer $ n (3≤n≤10^4)$, denoting the number of servers. The $ IP$ address of these servers is $ 1…n$.
Then follows $ n$ lines, each line contains two integers $ u$ and $ v$ $ (0≤u,v≤n)$, 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 (p≤50000)$, 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.


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

Sample Input

1 0
4 2
2 0
3 2
1 3
2 1

Sample Output



2017 ACM/ICPC Asia Regional Shenyang Online


本题的贪心策略 :

本题不是单纯地删除$lca(u,v)$,例如对于一条链上的$ (root,a1,a2,a3)$ $ lca(root, a1)=root$ $ lca(a1,a3)=a1 $;那么不是删去$ root$ 而是删去$ a1$即可断开两条通信恰好是lca深度较大的点应该删去,所以原本深度最小的$lca$没有必要删去


问题在于删去的点一定是$ lc$a,那么每次删去$ lca$后暴力$ dfs$,把删去$ lca$的子树的所有未被标记的点都标记一遍,这样标记算法$ O(N)$,N为子树节点数,然后按照点对$ lca$的深度从深到浅处理,如果当前点对两个有一个已经被标记,说明两点已经断开了,没有必要再次删除,否则断开,标记$ lca$子树。如此贪心即可。


//好题 lca+贪心
//题意:给出一棵有根树根节点标号 0,给出k个点对 (u,v)表示从u到v的路径(含u,v)上有一点坏掉,
#include <bits/stdc++.h>
using namespace std;
const  int maxn = 1e4 + 7;
struct query { int u,v,dep,lca;};
bool operator <(query a, query b)//排序lca深度
{return a.dep<b.dep;}
priority_queue<query> que;
#define clr(a,b) memset(a,b,sizeof(a));
bool vis[maxn];
namespace LCA {
    int head[maxn];
    int edge_tot;
    struct {int to,next;}edge[maxn<<1];
    void addedge(int u,int v) {
        edge[edge_tot].to = v;
        edge[edge_tot].next = head[u];
        head[u] = edge_tot ++;
    int son[maxn],dep[maxn],fa[maxn],id[maxn],sz[maxn],Top[maxn];
    int cnt;
    void dfs(int u,int pre,int d) {
        dep[u] = d; fa[u] = pre; sz[u] = 1;
        for(int i = head[u]; ~i; i = edge[i].next) {
            int v = edge[i].to;
            if(v != pre) {
                if(son[u]==-1 || sz[v]>sz[son[u]]) son[u]=v;
    void dfs2(int u,int sp) {
        Top[u] = sp;id[u] = cnt ++;
        if(son[u]==-1) return;
        dfs2(son[u], sp);
        for(int i=head[u]; ~i; i =edge[i].next) {
            int v = edge[i].to;
            if(v != son[u] &amp;&amp; v != fa[u])dfs2(v,v);
    int LCA(int x,int y) {
        return dep[x]<dep[y]?x:y;
    void init() {
        memset(son,-1, sizeof(son));
        memset(head,-1, sizeof(head));
        edge_tot = 0;
        cnt = 0;
void dfs(int u) {
    for(int i=LCA::head[u];~i;i=LCA::edge[i].next) {
        int v = LCA::edge[i].to;
        if(!vis[v]&amp;&amp;LCA::dep[v]>LCA::dep[u]) dfs(v);
int main() {
    int n;
    while(scanf("%d",&amp;n)!=EOF) {
        int ans = 0;
        for(int i=1;i<=n;i++) {
            int u,v;scanf("%d%d",&amp;u,&amp;v);//注意起点从0开始
        int q;scanf("%d",&amp;q);
        while(q--) {
            int u,v,lca,dep;
            scanf("%d %d",&amp;u,&amp;v);
            lca = LCA::LCA(++u,++v);
            dep = LCA::dep[lca];
        while(!que.empty()) {
            int u = que.top().u, v = que.top().v;
            int lca = que.top().lca;que.pop();
            if(vis[u]||vis[v]) continue;//两段点已经访问过pass
    return 0;
分类: 图论


电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.