• poj 3417 Network


    Description:

      先给出一棵无根树,然后下面再给出m条边,把这m条边连上,然后每次你能毁掉两条边,规定一条是树边,一条是新边,问有多少种方案能使树断裂。

    思路:

      当你在树上连边的时候,树就会形成一个环,然后把在环内切边,那么第二刀任意。如果一条边在两个环内,第二刀唯一,如果在两个以上环内,无解。

     也就是每次连边之后,求每条边的覆盖次数。应用树上差分(乱搞)算法可得解

    #include<iostream>
    #include<vector>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int N = 1e5 + 10, M = 2e5 + 10;
    typedef pair<int,int> P;
    
    int head[N], now;
    struct edges{
        int to, next;
    }edge[N<<1];
    void add(int u,int v){ edge[++now] = {v, head[u]}; head[u] = now;}
    
    int n, m, lca[N], fa[N], vis[N], w[N];
    vector<P> q[N];
    
    int get(int x){
        if(x != fa[x]) return fa[x] = get(fa[x]);
        return x;
    }
    void tarjan(int x){
        vis[x] = 1;
        for(int i = head[x]; i; i = edge[i].next){
            int v = edge[i].to;
            if(vis[v]) continue;
            tarjan(v);
            fa[v] = x;
        }
        for(int i = 0; i < q[x].size(); i++){
            int v = q[x][i].first, id = q[x][i].second;
            if(vis[v] == 2)
              lca[id] = get(v);
        }
        vis[x] = 2;
    }
    int ans[N];
    void dfs(int x){
        ans[x] = w[x], vis[x] = 1;
        for(int i = head[x]; i; i = edge[i].next){
            int v = edge[i].to;
            if(vis[v]) continue;
            dfs(v);
            ans[x] += ans[v];
        }
    }
    void init(){
        memset(w,0,sizeof(w));
        memset(edge,0,sizeof(edge)); now = 0;
        memset(head,0,sizeof(head));
        memset(ans,0,sizeof(ans));
        memset(vis,0,sizeof(vis));
        memset(lca,0,sizeof(lca));
    }
    int main(){
    //    freopen("wrong.in","r",stdin);
        while(scanf("%d%d", &n, &m) != EOF){
            init();
            int x, y;
            for(int i = 1; i <= n; i++) fa[i] = i;
            for(int i = 1; i < n; i++){
                scanf("%d%d",&x, &y);
                add(x, y); add(y, x);
            }
            for(int i = 1; i <= m; i++){
                scanf("%d%d",&x, &y);
                q[x].push_back(P(y, i));
                q[y].push_back(P(x, i));
                w[x]++, w[y]++;
                if(x == y) lca[i] = x;
            }
            tarjan(1);
            for(int i = 1; i <= m; i++)
              w[lca[i]] -= 2;
            memset(vis,0,sizeof(vis));
            dfs(1);
            int tot = 0;
            for(int i = 2; i <= n; i++){
                if(ans[i] == 0) tot += m;
                if(ans[i] == 1) tot++;
            }
            printf("%d
    ",tot);
            for(int i = 1; i <= n; i++)
              q[i].clear();
        }    
        return 0;
    }
  • 相关阅读:
    collections.ChainMap类合并字典或映射
    collections.namedtuple()命名序列元素
    过滤、修改和替换列表数据
    快速排序
    itertools.groupby()分组字典列表
    operator.attrgetter() 进行对象排序
    operator.itemgetter() 字典列表排序
    collections.Counter类统计列表元素出现次数
    递归
    正则表达式的一些题
  • 原文地址:https://www.cnblogs.com/Rorshach/p/8724480.html
Copyright © 2020-2023  润新知