zoukankan      html  css  js  c++  java
  • 10.16模拟赛

    sol:

    原题 CF444E

    引理:考虑把xi像size一样记录出某个子树的大小,如果这个子树的大小大于除这个子树外的节点数,那这条边就可以满足条件。

    但是不能用整个树来做判断,可以把他们看成一块块的,首先对每条边按边权排序,然后用并查集把点并起来,顺便把sz合起来,顺便同时判断是否满足

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N=100005;
    int n,fa[N],sz[N],bo=0,pp[N],S=0;
    inline int Find(int x){return (x==fa[x])?x:fa[x]=Find(fa[x]);}
    struct node{int x,y,w;}a[N];
    inline bool cmp(node a,node b){return a.w<b.w;}
    inline void merg(int x,int y)
    {
      fa[x]=y; sz[y]+=sz[x]; pp[y]+=pp[x]; if(sz[y]>S-pp[y])bo=1;
    }
    int main()
    {
      int i,x,y,re=0; scanf("%d",&n);
      for(i=1;i<n;i++)
      {
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w); fa[i]=i; sz[i]=1;
      }fa[n]=n; sz[n]=1; sort(a+1,a+n,cmp); for(i=1;i<=n;i++)scanf("%d",&pp[i]),S+=pp[i];
      for(i=1;i<n;i++)
      {
        if(bo)break; x=Find(a[i].x); y=Find(a[i].y); re=a[i].w; merg(x,y);
      }printf("%d
    ",re);
    }

     

    sol:树形DP,可知从一个点出发有两部分答案,一部分是在它的子树内的答案,另一部分是在子树外的。统计所有节点两部分的和就是答案了,代码实现挺妙的,

    #include <cstdio>
    using namespace std;
    const int N=200005,M=400005,B=155;
    int n,k,tot=0,Next[M],to[M],head[M],f[N][B],g[N][B];
    long long s1[N],s2[N],re=0;
    inline void add(int x,int y){Next[++tot]=head[x];to[tot]=y;head[x]=tot;}
    inline void dfs(int x,int fa)
    {
        int i,j; f[x][0]=1;
        for(i=head[x];i;i=Next[i]) if(to[i]!=fa)
        {
            dfs(to[i],x); for(j=0;j<k-1;j++)f[x][j+1]+=f[to[i]][j]; f[x][0]+=f[to[i]][k-1]; s1[x]+=(long long)s1[to[i]]+f[to[i]][0];
        }re+=s1[x];
    }
    inline void dfs1(int x,int fa)
    {
        int i,j;
        if(x!=1)
        {
            for(j=0;j<k-1;j++)g[x][j+1]+=g[fa][j]; g[x][0]+=g[fa][k-1]; s2[x]+=(long long)s2[fa]+g[fa][0]; re+=s2[x];
        }for(j=0;j<k;j++)g[x][j]+=f[x][j]; s2[x]+=s1[x];
        for(i=head[x];i;i=Next[i])if(to[i]!=fa)
        {
            for(j=0;j<k-1;j++)g[x][j+1]-=f[to[i]][j]; g[x][0]-=f[to[i]][k-1]; s2[x]-=(long long)s1[to[i]]+f[to[i]][0]; dfs1(to[i],x);
            for(j=0;j<k-1;j++)g[x][j+1]+=f[to[i]][j]; g[x][0]+=f[to[i]][k-1]; s2[x]+=(long long)s1[to[i]]+f[to[i]][0];
        }
    }
    int main()
    {
        int i,x,y; scanf("%d%d",&n,&k);
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y); add(x,y); add(y,x);
        }dfs(1,0); dfs1(1,0); printf("%lld
    ",1LL*re/2LL);
    }
    View Code
  • 相关阅读:
    POJ2001Shortest Prefixes[Trie]
    UVA
    POJ2528Mayor's posters[线段树 离散化]
    COGS130. [USACO Mar08] 游荡的奶牛[DP]
    POJ1962Corporative Network[带权并查集]
    BZOJ1798: [Ahoi2009]Seq 维护序列seq[线段树]
    洛谷U4859matrix[单调栈]
    COGS247. 售票系统[线段树 RMQ]
    COGS1008. 贪婪大陆[树状数组 模型转换]
    COGS182 [USACO Jan07] 均衡队形[RMQ]
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/9800817.html
Copyright © 2011-2022 走看看