hdu 6161

来源:互联网 发布:windows 桌面版qq 编辑:程序博客网 时间:2024/05/18 00:46

题目链接:点击打开链接


题解思路:求通过此点求最大路径和无非两种:1.路径通过节点的两个儿子2.路径通过节点的一个儿子和自己父节点的另一个儿子,那么我们用dp[i]表示节点i通过他的一个儿子到叶子节点最大和,那么就可以递推更新答案了。


代码:

#include <queue>#include <algorithm>#include <cmath>#include <cstdio>#include <iostream>#include <cstring>#include <set>#include <map>using namespace std;typedef long long ll;const int mx = 1e5+10;int n,m;char str[20];map<int,ll>val,dp;ll cal(ll x){    if(x>n) return 0;    if(dp.count(x)) return dp[x];    ll lson = 0,rson = 0,ts;    ts = x;    while((ts<<1)<=n){        ts <<= 1;        lson++;    }    ts = x;    while((ts<<1|1)<=n){        ts = (ts<<1|1);        rson++;    }    if(rson!=lson) ts = n;    ll ret = 0;    while(ts>=x){        ret += (val.count(ts)?val[ts]:ts);        ts >>= 1;    }    return ret;}void update(ll x,ll v){    val[x] = v;    while(x){        dp[x] = max(cal(x<<1),cal(x<<1|1))+(val.count(x)?val[x]:x);        x >>= 1;    }}ll query(ll x){    ll ans = cal(x<<1)+cal(x<<1|1)+(val.count(x)?val[x]:x);    ll ret = cal(x);    while((x>>1)){        int flag = (x%2);        x >>= 1;        ret += (val.count(x)?val[x]:x);        if(flag) ans = max(ans,ret + cal(x<<1));        else ans = max(ans,ret + cal(x<<1|1));    }    return ans;}int main(){    while(~scanf("%d%d",&n,&m)){        ll x , y;        val.clear(); dp.clear();        while(m--){            scanf("%s",str);            if(str[0]=='q'){  scanf("%lld",&x);  printf("%lld\n",query(x));  }            else {  scanf("%lld%lld",&x,&y);  update(x,y);  }        }    }    return 0;}


原创粉丝点击