您的位置:首页 > 其它

HDU-5242 Game (贪心&&树链剖分&&线段树)

2016-03-19 18:53 435 查看

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=5242

题意:

给出一颗以1节点为根的树,每个节点有各自的价值,有m次从根节点出发向下走到叶子节点的机会,每次会得到所有经过节点的权值,每个节点只有在第一次经过时有价值,求m次之后能够获得的最大权值。

思路:

典型的树链剖分题,只要找到所有重链的权值然后贪心找前m个的和就行了。

具体解法就是先dfs找到所有叶子节点从根走下来得到的总权值,排序之后将有重复路径的节点权值减去,这就是一个找重链的过程,对于每个节点,他的所有儿子中能够找到最大权值链的那一条就是和这个节点在同一条重链上的,其他儿子节点作为其他重链的新起点,最后结构造出了一个包含重链的树。每个节点都一定且仅在一条重链中,并且每条重链都包含一个叶子节点,所以只要找到权值最大的m条重链就是最大总权值了。

一开始并没有想到写树链剖分,用线段树写的。

前面的处理一样,找到每个叶子节点的总权值,然后以叶子节点建树。在dfs找叶子节点总权值时回溯处理出来每个节点在这个线段树中包含的区间。然后线段树求m次最大值就行了。每次query之后从该叶子节点向上搜索找到他的所有父节点对这些父节点在线段树中包含的叶子节点都进行区间更新,就是都减去这个节点的权值,保证已经更新过的节点就不更新了,所以整个更新的复杂度为O(n*logn)。找最大的m个节点的复杂度是O(m*logn)。

所以树链剖分的复杂度是O(2*n),线段树叶子节点是O(n*logn+m*logn),实际表现差不多。

代码:

树链剖分:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define EPS 1e-6
#define N 112345
using namespace std;
struct node
{
long long val,id;
friend bool operator < (node a, node b)
{
return a.val > b.val;
}
}p
;
long long n,m,res,flag,tot;
vector<long long>zi
;
long long fa
,val
,ans
;
bool vis
;
void init()
{
for(int i=0;i<=n;i++)zi[i].clear();
memset(vis,0,sizeof(vis));
res=0;tot=0;
}
void dfs(long long now, long long vall)
{
int num=zi[now].size();
if(num==0)
p[tot].id=now, p[tot++].val=val[now]+vall;
else
for(int i=0;i<num;i++)
dfs(zi[now][i],vall+val[now]);
}
long long dfs1(long long now)
{
if(vis[now])return 0;
vis[now]=1;
return val[now]+dfs1(fa[now]);
}
int main()
{
long long i,j,k,kk,cas,T,t,x,y,z;
scanf("%I64d",&T);
cas=0;
while(T--)
{
scanf("%I64d%I64d",&n,&m);
init();
for(i=1;i<=n;i++)scanf("%I64d",&val[i]);
for(i=1;i<n;i++)
{
scanf("%I64d%I64d",&x,&y);
zi[x].push_back(y);
fa[y]=x;
}
dfs(1,0);
sort(p,p+tot);
for(i=0;i<tot;i++)
ans[i]=dfs1(p[i].id);
sort(ans,ans+tot);
for(i=tot-1,j=0;i>=0&&j<m;j++,i--)res+=ans[i];
printf("Case #%I64d: %I64d\n",++cas,res);
}
return 0;
}


线段树:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define EPS 1e-6
#define N 112345
using namespace std;
struct node
{
long long sum,side;
}sum[N<<2],ttt;
long long n,res,flag,tot;
long long a
,b
,hehe
,xixi
;
#define root 1 , tot , 1
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
vector<long long>zi
;
long long fa
;
bool vis
;
long long val
;
long long add[N<<2];
void pushUp(long long rt)
{
if(sum[rt<<1].sum>=sum[rt<<1|1].sum)
{
sum[rt]=sum[rt<<1];
}
else
{
sum[rt]=sum[rt<<1|1];
}
}
void pushDown(long long l,long long r,long long rt)
{
if(add[rt])
{
long long m = (l+r)>>1;
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
sum[rt<<1].sum += add[rt];
sum[rt<<1|1].sum += add[rt];
add[rt] = 0;
}
}
void update(long long l,long long r,long long rt,long long ql,long long qr,long long val)
{
if(l>qr||ql>r)return;
if(l>=ql&&r<=qr)
{
sum[rt].sum += val;
add[rt] += val;
return;
}
pushDown(l,r,rt);
long long m = (l+r)>>1;
if(ql<=m)update(lson,ql,qr,val);
if(qr>m)update(rson,ql,qr,val);
pushUp(rt);
}
void build(long long l,long long r,long long rt)
{
add[rt]=0;
if(l == r)
{
sum[rt].sum=hehe[res++];
sum[rt].side=xixi[res-1];
return;
}
long long m = (l+r)>>1;
build(lson);
build(rson);
pushUp(rt);
}
node query(long long l,long long r,long long rt,long long ql,long long qr)
{
if(l>qr||ql>r)
return ttt;
if(l>=ql&&r<=qr)
return sum[rt];
pushDown(l,r,rt);
long long m = l+r>>1;
node x=query(l,m,rt<<1,ql,qr);
node y=query(m+1,r,rt<<1|1,ql,qr);
return x.sum>=y.sum?x:y;
}
void init()
{
for(int i=0;i<=n;i++)zi[i].clear();
memset(vis,0,sizeof(vis));
ttt.sum=-1;
}
void dfs(int now,long long vall)
{
long long len=zi[now].size();
if(len==0)
{
hehe[tot++]=val[now]+vall;
xixi[tot-1]=now;
a[now]=b[now]=tot-1;
return ;
}
for(int i=0;i<len;i++)
dfs(zi[now][i],vall+val[now]);
long long x=INF,y=-1;
for(int i=0;i<len;i++)
{
x=min(x,a[zi[now][i]]);
y=max(y,b[zi[now][i]]);
}
a[now]=x;b[now]=y;
}
void dfs1(long long now)
{
if(vis[now])return;
vis[now]=true;
update(root,a[now]+1,b[now]+1,-val[now]);
if(now==1)return;
dfs1(fa[now]);
}
int main()
{
long long i,j,k,kk,cas,T,t,x,y,z;
scanf("%I64d",&T);
cas=0;
while(T--)
{
long long m;
scanf("%I64d%I64d",&n,&m);
init();
for(i=1;i<=n;i++)scanf("%I64d",&val[i]);
for(i=1;i<n;i++)
{
scanf("%I64d%I64d",&x,&y);
zi[x].push_back(y);
fa[y]=x;
}
tot=0;
dfs(1,0);
res=0;
build(root);
long long res=0;
for(i=0;i<m;i++)
{
node t=query(root,1,tot);
res+=t.sum;
dfs1(t.side);
}
printf("Case #%I64d: %I64d\n",++cas,res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: