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\n",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\n",1LL*re/2LL);
}
View Code

 

posted @ 2018-10-16 21:30  yccdu  阅读(125)  评论(0编辑  收藏  举报