• 【COGS 2434】 暗之链锁 树上差分+LCA


    差分就是把一个值拆成许多差的和如 1 2 4 6 9 那么 把这个东西拆成 1 1 2 2 3 就是了,当然也可以理解为对一个问题分解为多个子问题并对其进行操作来得到原问题的答案。

    树上差分就更玄妙了,它既可以把原问题拆成他到根节点的所有点,也可以拆成子树,拆成子树的话修改一个点影响的是他到根的路径上所有点,根据这个我们可以再加上LCA来解决许多问题。

    这道题:I. 我们可以看出我们可以把它转化成一棵有根树,那么两部分一定是一个子树和其他 II. 那些虚边,都是砍断实边之后的藕断丝连,至于如何计算在这个实边上附上的虚边我们只需把那些虚路径乎到实路径上,就是路径修改. 

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #define MAXN 100010
    using namespace std;
    inline int read()
    {
        int sum=0;
        char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')
        {
          sum=(sum<<1)+(sum<<3)+ch-'0';
          ch=getchar();
        }
        return sum;
    }
    int w[MAXN],n,m;
    int f[MAXN];
    struct VIA
    {
      int to,next;  
    }c[MAXN<<1],q[MAXN<<2];
    int head[MAXN],t,Head[MAXN],T;
    bool v[MAXN];
    inline void add(int x,int y)
    {
      c[++t].to=y;
      c[t].next=head[x];
      head[x]=t;
    }
    inline void Add(int x,int y)
    {
      q[++T].to=y;
      q[T].next=Head[x];
      Head[x]=T;
    }
    inline void Init()
    {
       n=read(),m=read();
       for(int i=1,x,y;i<n;++i)x=read(),y=read(),add(x,y),add(y,x);
       for(int i=1,x,y;i<=m;++i)
       {
         x=read(),y=read();
         if(x==y)continue;
         Add(x,y),++w[x],++w[y],Add(y,x);
       }
    }
    inline int find(int x)
    {
       return x==f[x]?x:(f[x]=find(f[x]));
    }
    void LCA(int x,int p)
    {
       f[x]=x;
       for(int i=head[x];i;i=c[i].next)
       if(c[i].to!=p)
       {
         LCA(c[i].to,x);
         f[c[i].to]=x;
       }
       v[x]=1;
       for(int i=Head[x];i;i=q[i].next)
        if(v[q[i].to])
         w[find(q[i].to)]-=2;
    }
    int ans;
    void dfs(int x)
    {
       v[x]=0;
       for(int i=head[x];i;i=c[i].next)
        if(v[c[i].to])
        {
          dfs(c[i].to);
          w[x]+=w[c[i].to];
        }
    }
    inline void work()
    {
       LCA(1,0);
       dfs(1);
       for(int i=2;i<=n;++i)
        if(w[i]==0) ans+=m;
        else if(w[i]==1) ++ans;
       printf("%d",ans);
    }
    int main()
    {
        Init();
        work();
        return 0;
    }
  • 相关阅读:
    使用vs2010生成SQL Server 随机数据
    关于范式的一些简单理解
    SQL Server 中的逻辑读与物理读
    关于SQLServer 中行列互转的实例说明
    SQL Server2012新特性概述
    讨论关于RAID以及RAID对于存储的影响
    eclipse配置mybatis xml文件自动提示(转)
    eclipse自动添加注释
    模拟点击事件在alert前不起作用
    SSM提交了事物但数据库不执行
  • 原文地址:https://www.cnblogs.com/TSHugh/p/7241827.html
Copyright © 2020-2023  润新知