hdu 5242 树链剖分思想或优先队列贪心

hdu5242
优先队列按树的深度在top,深度相同 值大的在top,所以贪心 从树底层往上走,这样能使得到达树顶一定是最大的。

//#include <bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<stdlib.h>
#include<time.h>
#include <iomanip>
#define lowbit(x) (x&(-x))
#define inf  0x7fffffff
#define linf 0x7fffffffffffffff
#define fil(x,y) memset(x,y,sizeof(x))
#define fup(i,x,y) for(int i=(x);i<=(y);i++)
#define fdn(i,x,y) for(int i=(x);i>=(y);i--)
#define sp(x) setprecision(x)
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define sld(n) scanf("%lld",&n)
#define sldd(n,m) scanf("%lld%lld",&n,&m)
#define slddd(n,m,k) scanf("%lld%lld%lld",&n,&m,&k)
#define sf(n) scanf("%lf",&n)
#define sff(n,m) scanf("%lf%lf",&n,&m)
#define sfff(n,m,k) scanf("%lf%lf%lf",&n,&m,&k)
#define sc(n) scanf("%s",n)
#define pf(x) printf("%d\n",x)
#define pfl(x) printf("%lld\n",x)
#define pff(x) printf("%lf\n",x)
#define debug printf("!!\n");
#define N 1000005
#define M 4000009

#define pi acos(-1)
#define eps 1e-2
//cout.setf(ios::fixed);
//freopen("out.txt","w",stdout);// freopen("in.txt","r",stdin);
using namespace std;
typedef long long  ll;
typedef double db;
struct node
{
    int x;
    ll sum;
    int deep;
    bool operator <(const node b) const
    {
        if(deep==b.deep) return sum<b.sum;
        return deep<b.deep;
    }
};
int vis[100005],pre[100005];ll deep[100005];
ll a[100005];
vector<int> q[100005];
priority_queue<node> s;
int m,maxx=0;;
void dfs(int x,int dp)
{
    deep[x]=dp;
    for(int i=0;i<q[x].size();i++)
    {
        dfs(q[x][i],dp+1);
    }
    if(q[x].size()==0)  s.push(node{x,a[x],dp});
}
int main()
{
    int t,kk=1;
    sd(t);
    while(t--)
    {
        while(!s.empty()) s.pop();
        fil(vis,0);
        fil(pre,0);
        fil(deep,0);
        m=0;
        int n,k;
        sdd(n,k);
        fup(i,1,n)
            sld(a[i]),q[i].clear();
        fup(i,1,n-1)
        {
            int x,y;
            sdd(x,y);
         //   q[x].push_back(y);
            pre[y]=x;
            q[x].push_back(y);
        }
        dfs(1,1);
        ll ans=a[1];
        vis[1]=1;
        a[1]=0;
        while(!s.empty())
        {
            node tp=s.top();
        //    pf(tp.x);
     //       cout<<tp.x<<' '<<tp.sum<<endl;
            s.pop();
            if(tp.x==1)
            {
            //    pf(tp.sum);
                k--;
                ans+=tp.sum;
                if(!k) break;
            }
            else if(vis[tp.x])
            {
                s.push(node{1,tp.sum,1});
            }
            else
            {
                a[tp.x]=0;
                vis[tp.x]=1;
                s.push(node{pre[tp.x],tp.sum+a[pre[tp.x]],deep[pre[tp.x]]});
                a[pre[tp.x]]=0;
            }
        }
            printf("Case #%d: ",kk++);
        if(n!=1) pfl(ans);
        else pf(1);
    }
    return 0;
}

树剖

//#include <bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<stdlib.h>
#include<time.h>
#include <iomanip>
#define lowbit(x) (x&(-x))
#define inf  0x7fffffff
#define linf 0x7fffffffffffffff
#define mem(x,y) memset(x,y,sizeof(x))
#define fup(i,x,y) for(int i=(x);i<=(y);i++)
#define fdn(i,x,y) for(int i=(x);i>=(y);i--)
#define sp(x) setprecision(x)
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define sld(n) scanf("%lld",&n)
#define sldd(n,m) scanf("%lld%lld",&n,&m)
#define slddd(n,m,k) scanf("%lld%lld%lld",&n,&m,&k)
#define sf(n) scanf("%lf",&n)
#define sff(n,m) scanf("%lf%lf",&n,&m)
#define sfff(n,m,k) scanf("%lf%lf%lf",&n,&m,&k)
#define sc(n) scanf("%s",&n)
#define pf(x) printf("%d\n",x)
#define pfl(x) printf("%lld\n",x)
#define pff(x) printf("%lf\n",x)
#define N 100100
#define M 4000009

#define pi acos(-1)
#define eps 1e-2
using namespace std;
typedef long long ll;
const int maxn=1011;
struct edge
{
    int d,next;
    edge():next(-1){}
}e[2*N];
int son[N],n;
int head[N];
int which=1;
ll val[N],down[N];
void add1(int s,int d)
{
    e[which].d=d;
    e[which].next=head[s];
    head[s]=which++;
}
void dfs1(int x,int fa)
{
    int res=val[x];
    for(int i=head[x];i!=-1;i=e[i].next)
    {
        int to=e[i].d;
        if(to!=fa)
        {
            dfs1(to,x);
            if(down[to]>down[son[x]]) son[x]=to;
        }
    }
    down[x]=res+down[son[x]];
}
int cnt;
ll a[N];
void dfs2(int x,ll t)
{
    if(!son[x])
    {
        a[++cnt]=t;
        return ;
    }
    dfs2(son[x],t+val[son[x]]);
    for(int i=head[x];i!=-1;i=e[i].next)
    {
        int to=e[i].d;
        if(to!=son[x]) dfs2(to,val[to]);
    }
}
int main()
{
    //freopen("data","r",stdin);
    int t,cas=1;
    sd(t);
    while(t--)
    {
        which=1;
        mem(head,-1);

        int n,m;
        sdd(n,m);
        fup(i,1,n)
            sld(val[i]);
        fup(i,1,n-1)
        {
            int x,y;
            sdd(x,y);
            add1(x,y);
        }
        mem(son,0);
        dfs1(1,0);
   //     puts("1");
        cnt=0;
        dfs2(1,val[1]);
  //      puts("1");
        sort(a+1,a+1+cnt);
        ll ans=0;
        fdn(i,cnt,1)
        {
            if(!m) break;
            ans+=a[i];
            m--;
        }printf("Case #%d: " , cas++);
        pfl(ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于HDU4546问题,还可以使用优先队列(Priority Queue)来解决。以下是使用优先队列的解法思路: 1. 首先,将数组a进行排序,以便后续处理。 2. 创建一个优先队列(最小堆),用于存储组合之和的候选值。 3. 初始化优先队列,将初始情况(即前0个数的组合之和)加入队列。 4. 开始从1到n遍历数组a的元素,对于每个元素a[i],将当前队列中的所有候选值取出,分别加上a[i],然后再将加和的结果作为新的候选值加入队列。 5. 重复步骤4直到遍历完所有元素。 6. 当队列的大小超过k时,将队列中的最小值弹出。 7. 最后,队列中的所有候选值之和即为前k小的组合之和。 以下是使用优先队列解决HDU4546问题的代码示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); // 对数组a进行排序 priority_queue<long long, vector<long long>, greater<long long>> pq; // 最小堆 pq.push(0); // 初始情况,前0个数的组合之和为0 for (int i = 0; i < n; i++) { long long num = pq.top(); // 取出当前队列中的最小值 pq.pop(); for (int j = i + 1; j <= n; j++) { pq.push(num + a[i]); // 将所有加和结果作为新的候选值加入队列 num += a[i]; } if (pq.size() > k) { pq.pop(); // 当队列大小超过k时,弹出最小值 } } long long sum = 0; while (!pq.empty()) { sum += pq.top(); // 求队列中所有候选值之和 pq.pop(); } cout << sum << endl; return 0; } ``` 使用优先队列的方法可以有效地找到前k小的组合之和,时间复杂度为O(nklog(k))。希望这个解法对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值