zoukankan      html  css  js  c++  java
  • 暗之链锁

    【题目描述】

    传说中的暗之连锁被人们称为Dark。Dark是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它。经过研究,你发现Dark呈现无向图的结构,图中有N个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark有N – 1条主要边,并且Dark的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark还有M条附加边。

    你的任务是把Dark斩为不连通的两部分。一开始Dark的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark就会进入防御模式,主要边会变为无敌的而附加边可以被切断。但是你的能力只能再切断

    Dark的一条附加边。现在你想要知道,一共有多少种方案可以击败Dark。注意,就算你第一步切断主要边之后就已经把Dark斩为两截,你也需要切断一条附加边才算击败了Dark。

    【输入格式】

    第一行包含两个整数N和M。

    之后N – 1行,每行包括两个整数A和B,表示A和B之间有一条主要边。

    之后M行以同样的格式给出附加边。

    【输出格式】

    输出一个整数表示答案。

    【样例输入】

    4 1

    1 2

    2 3

    1 4

    3 4

    【样例输出】

    3

    【提示】

    自己瞎做吧

    【数据范围】

    对于20% 的数据,N≤100,M≤100。

    对于100% 的数据,N≤100 000,M≤200 000。数据保证答案不超过2^31– 1。

    【题解】

        第一道树上差分。差分,就是在大都市meg里面学到的那种开头减,结尾加,前缀和来看状态的方法,例题还有一道借教室(不是换教室!)。在树上差分可以表示出两点之间的路径,只要在两端点均+1,LCA-2,最后用dfs统计和就可以了。过去学的LCA有朴素、ST、tarjan离线、在线、倍增,这次用的是tarjan,大概也是我最熟练的一种:两次头插法分别加双向边和存问题,还要用到并查集。差分、LCA、dfs三个步骤结束后得到每条实边被x条虚边覆盖,x=0的实边对答案有m的贡献,x=1的实边对答案有1的贡献。学长们出的加强版需要删掉不止一条虚边一条实边,如果边有富裕的话就会产生一个组合数的贡献,计算组合数大概是ad学长上次讲到的那些方法,数据小递推就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int sj=200010;
    int n,m,po[sj/2],a1,a2,jg,h[sj],l[sj],ans[sj],e,f;
    int fa[sj/2],zx[sj/2],re[sj/2],dep[sj/2];
    struct B
    {
        int u,v,ne;
    }b[sj];
    struct Q
    {
        int u,v,ne,num;
    }q[sj*2];
    void add(int x,int y)
    {
         b[e].u=x;
         b[e].v=y;
         b[e].ne=h[x];
         h[x]=e++;
    }
    int find(int x)
    {
         if(fa[x]==-1) return x;
         fa[x]=find(fa[x]);
         return fa[x];
    }
    void hb(int x,int y)
    {
         x=find(x);
         y=find(y);
         if(x!=y) fa[x]=y;
    }
    void lca(int x)
    {
         zx[x]=x;
         re[x]=1;
         for(int i=h[x];i!=-1;i=b[i].ne)
            if(!re[b[i].v])
            {
               lca(b[i].v);
               hb(x,b[i].v);
               zx[find(b[i].v)]=x;
            }
         for(int i=l[x];i!=-1;i=q[i].ne)
            if(re[q[i].v])
              ans[q[i].num]=zx[find(q[i].v)];
    }
    void adq(int x,int y,int z)
    {
         q[f].u=x;
         q[f].v=y;
         q[f].num=z;
         q[f].ne=l[x];
         l[x]=f++;
    }
    void dfs(int x)
    {
         for(int i=h[x];i!=-1;i=b[i].ne)
           if(!re[b[i].v])
           {
              re[b[i].v]=1;
              dep[b[i].v]=dep[x]+1;
              dfs(b[i].v);
              po[x]+=po[b[i].v];
           }
    }
    int main()
    {
        //freopen("t.txt","r",stdin);
        freopen("yam.in","r",stdin);
        freopen("yam.out","w",stdout);
        scanf("%d%d",&n,&m);
        memset(h,-1,sizeof(h));
        memset(fa,-1,sizeof(fa));
        memset(l,-1,sizeof(l));
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&a1,&a2);
            add(a1,a2);
            add(a2,a1);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a1,&a2);
            adq(a1,a2,i);
            adq(a2,a1,i);
            po[a1]++;
            po[a2]++;
        }
        lca(1);
        for(int i=1;i<=m;i++)
          po[ans[i]]-=2;
        memset(re,0,sizeof(re));
        re[1]=1;
        dep[1]=1;
        dfs(1);
        for(int i=0;i<e;i+=2)
        {
          if(dep[b[i].v]<dep[b[i].u])
          {
            if(po[b[i].u]==0) jg+=m;
            else if(po[b[i].u]==1) jg++;
          }
          if(dep[b[i].v]>dep[b[i].u])
          {
            if(po[b[i].v]==0) jg+=m;
            else if(po[b[i].v]==1) jg++;
          }
        }
        printf("%d",jg);
        //while(1);
        return 0;
    }
  • 相关阅读:
    Live2d Test Env
    Live2d Test Env
    Live2d Test Env
    图神经网络入门
    CommandLineRunner 可能会导致你的应用宕机停止,我劝你耗子尾汁
    不使用 MQ 如何实现 pub/sub 场景?
    为什么 @Value 可以获取配置中心的值?
    vite + ts 快速搭建 vue3 项目 以及介绍相关特性
    给 Mac 添加右键菜单「使用 VSCode 打开」
    【Python】连接常用数据库
  • 原文地址:https://www.cnblogs.com/moyiii-/p/7241638.html
Copyright © 2011-2022 走看看