zoukankan      html  css  js  c++  java
  • 树上差分(poj3417)

    传送门

    对题意的转化其实挺巧妙的。

    可以看出来是在树上再加“附加边”,加了附加边的即形成环。形成环的定要删除一条主要边和一条附加边才能分为两部分。

    如添加了附加边(x,y),相当于x到y的所有“主要边”被覆盖一次。

    若第一步把被覆盖0次的主要边切断,第二步可任意切断一条附加边。

    若第一步把被覆盖1次的主要边切断,第二步可切断的附加边唯一。

    若第一步把被覆盖2次及以上的主要边切断,第二步无论切断哪一条附加边都不能分成两部分。

    转化为区间修改,单点查询,显然差分思想,只不过是在树上,所以与lca有关(用这道题来复习一下lca)

    最后只要枚举每一条边看被覆盖几次,这里我们用一个数组cha[i]表示i上面的那条边被覆盖的次数

    (点表示对应的边也是很重要的思想)

    cha[a]++;cha[b]++;cha[LCA(a,b)]-=2;

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 100003
    using namespace std;
    struct EDGE{
        int nextt,to;
    }w[N*2];
    int head[N],dep[N],f[N][22],cha[N];
    int tot=0;
    int read()
    {
        int f=1,x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void add(int a,int b)
    {
        tot++;
        w[tot].nextt=head[a];
        w[tot].to=b;
        head[a]=tot;
    }
    void dfs1(int x)
    {
        for(int i=head[x];i;i=w[i].nextt)
        {
            int y=w[i].to;
            if(y==f[x][0])continue;
            f[y][0]=x;
            dep[y]=dep[x]+1;
            for(int i=1;i<20;++i)f[y][i]=f[f[y][i-1]][i-1];
            dfs1(y);
        }
    }
    int LCA(int x,int y)
    {
        if(dep[x]<dep[y])swap(x,y);
        for(int i=19;i>=0;--i)if(dep[f[x][i]]>=dep[y])x=f[x][i];
        if(x==y)return x;
        for(int i=19;i>=0;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    void dfs2(int x)
    {
        for(int i=head[x];i;i=w[i].nextt)
        {
            int y=w[i].to;
            if(y==f[x][0])continue;
            dfs2(y);
            cha[x]+=cha[y]; 
        }
    }
    int main()
    {
        int n=read(),m=read();
        for(int i=1;i<n;++i)
        {
            int a=read(),b=read();
            add(a,b);add(b,a);
        }
        dfs1(1);
        for(int i=1;i<=m;++i)
        {
            int a=read(),b=read();
            cha[a]++;cha[b]++;
            cha[LCA(a,b)]-=2;
        }
        dfs2(1);
        int ans=0;
        for(int i=2;i<=n;++i)
        {
            if(cha[i]==1)ans++;
            if(cha[i]==0)ans+=m;
        }
        printf("%d
    ",ans);
    }
    View Code

    复健真的好痛苦(枯了)

  • 相关阅读:
    从头认识java-14.2 进一步了解数组
    移植MonkeyRunner的图片对照和获取子图功能的实现-UiAutomator/Robotium篇
    JVM —— 移除永久代
    三层架构与四大天王之——查
    unity3D中使用Socket进行数据通信(一)
    npm使用指南
    java命令模式
    共享内存通讯编程
    jade 入门
    MongoDB数据库进阶 --- 增删查改...
  • 原文地址:https://www.cnblogs.com/yyys-/p/15243282.html
Copyright © 2011-2022 走看看