题目链接:http://codeforces.com/contest/796/problem/D
题目大意:有一棵树,有n个消防点。每个点到最近消防点的距离<=d。题目满足这个条件。问你最多可以拆多少条边,使这个条件仍然满足。

思路:
刚开始我的思路是dfs每个消防点,如果距离>d拆。或者遇到消防点拆。
这个思路的问题在:

如图d=3,那么拆掉红色的,那么1点就不满足了。

正确的思路:因为题目已经满足这个条件。那么我们就相当于把一棵树拆成森林。每个节点属于最近的那个消防点的子树。对每个消防点进行bfs。如果这个点已经访问过,那么说明他距离别的消防点更近,不属于这个消防点。这条边可以拆,注意标记边,访问过的边不能再访问。

#include <bits/stdc++.h>
using namespace std;

struct node{
    int v;
    int i;
};
vector<node> v[300005];
set<int> s;
bool vis[600005]={0};
int dn[300005]={0};
vector<int> sc;
map<int, int> mp;
queue<int> q;

void bfs(){

    while(!q.empty()){
        int u=q.front();
        q.pop();

        for(int i=0 ;i<v[u].size(); i++){
            node to=v[u][i];
            int vv=to.v, ii=to.i;

            if(vis[ii]){
                continue;
            }
            vis[ii]=1;

            if(dn[vv]){
                sc.push_back(ii);
            }
            else{
                dn[vv]=1;
                q.push(vv);
            }
        }
    }

    return ;
}

int main(){

    int n, m, d;
    scanf("%d%d%d", &n, &m, &d);
    for(int i=1; i<=m; i++){
        int x;
        scanf("%d", &x);
        s.insert(x);
        dn[x]=1;
        mp[x]=1;
    }
    for(int i=1; i<=n-1; i++){
        int x, y;
        scanf("%d%d", &x, &y);
        v[x].push_back(node{y, i});
        v[y].push_back(node{x, i});
    }
    for(set<int>::iterator p=s.begin(); p!=s.end(); p++){
        q.push(*p);
    }
    bfs();
    printf("%d\n", sc.size());
    for(int i=0; i<sc.size(); i++){
        printf("%d ", sc[i]);
    }

    return 0;
}