【bzoj2286】【SDOI2011】消耗战

14 篇文章 0 订阅
G - 消耗战

题意

  一棵有 n 个节点的树,删除一条边的代价是Wi
  有 Q 个询问,每个询问给出Ki个点,我们可以删除若干条边使得这些点与根节点(1号点)不连通,求最小代价

解法

虚树+树型 DP
  首先设 fu 表示解决掉 u u的子树的最小花费, Vu 表示 u 的父边的边权,那么显然有:
  fu=minfvVuv u 的孩子
  这样做的话,每一次都需要遍历整棵树,所以复杂度是O(Qn
  可以发现,在进行 dfs 的时候,会经过很多没有用的点,所以考虑将这些点去掉,留下需要用到的点,那么这个过程就是构建一棵虚树,这样的话,复杂度就可以变为O( Kilogn
  所以本题的重点就变成了怎么构建虚树,这里推荐一个博客,大家可以看看:http://www.cnblogs.com/chenhuan001/p/5639482.html

复杂度

O( Kilogn

代码

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#define Rint register int
#define Lint long long int
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=250010;
struct node
{
    int next,to,w;
}t[MAXN*2];
int head[MAXN],num;
int fa[MAXN][20],w[MAXN][20];
int dep[MAXN],island[MAXN];
int dfn[MAXN],q[MAXN];
Lint f[MAXN],g[MAXN];
int n,m,k,top,cnt;
void add(int u,int v,int w)
{
    t[++num]=(node){ head[u],v,w };
    head[u]=num;
}
void dfs(int k)
{
    dfn[k]=++cnt;
    for(int i=head[k],x; i ;i=t[i].next)
    {
        x=t[i].to;
        if( dfn[x] )   continue ;
        dep[x]=dep[k]+1,fa[x][0]=k;
        w[x][0]=t[i].w;
        dfs( x );
    }
}
int LCA(int u,int v)
{
    if( dep[u]<dep[v] )   swap( u,v );
    int f=dep[u]-dep[v];
    for(int i=19;i>=0;i--)
        if( (1<<i)&f )   u=fa[u][i];
    if( u==v )   return u;
    for(int i=19;i>=0;i--)
        if( fa[u][i]!=fa[v][i] )
            u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
int get(int u,int v)
{
    int ret=INF;
    for(int i=19;i>=0;i--)
        if( fa[u][i] && dep[fa[u][i]]>=dep[v] )   ret=min( ret,w[u][i] ),u=fa[u][i];
    return ret;
}
void init()
{
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++)
        {
            fa[i][j]=fa[fa[i][j-1]][j-1];
            w[i][j]=min( w[fa[i][j-1]][j-1],w[i][j-1] );
        }
}
int cmp(int x,int y)
{
    return dfn[x]<dfn[y];
}
int main()
{
    int u,v,w;
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add( u,v,w ),add( v,u,w );
    }
    scanf("%d",&m);
    dfs( 1 ),init();
    while( m-- )
    {
        scanf("%d",&k),top=0;
        for(int j=1;j<=k;j++)   scanf("%d",&island[j]);
        sort( island+1,island+k+1,cmp );
        q[++top]=1;
        f[1]=0,g[1]=0;
        for(int i=1;i<=k;i++)
        {
            u=LCA( q[top],island[i] );
            while( dep[q[top]]>dep[u] )
                if( dep[q[top-1]]<=dep[u] )
                {
                    w=min( g[top] ? INF : f[top] , (Lint)get( q[top],u ) );
                    top--;
                    if( u!=q[top] )   q[++top]=u,f[top]=g[top]=0;
                    f[top]+=w;
                    break ;
                }
                else
                {
                    f[top-1]+=min( g[top] ? INF : f[top] , (Lint)get( q[top],q[top-1] ) );
                    top--;
                }
            if( q[top]!=island[i] )   q[++top]=island[i],f[top]=0;
            g[top]=1;
        }
        while( top>1 )   f[top-1]+=min( g[top] ? INF : f[top] , (Lint)get( q[top],q[top-1] ) ),top--;
        printf("%lld\n",f[1]);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值