HDU 6161 Big binary tree

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6161

题意:给你一颗二叉树,每个节点的值为自身,接下来有2种操作

query:查询经过该点的路径的最大值

change:将一个点的值改变
 
官方题解:
考虑dp,f(x)表示从点x开始向下走得到的最大的点权和,查询直接从x开始向上走更新答案即可。
考虑快速算 f(x) 对于子树内没有被修改过的点的 f(x) 可以快速分类讨论算出,而不满足本条件的点只有 O(mlogm) 个,在hash上dp即可。
 
f(x)用贪心进行计算,先看左右儿子的深度,如果相同则选择右儿子走到底,否则最后应该选择n为最后的节点
查询时需要枚举所有情况
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define l(X) (X<<1)
#define r(X) (X<<1|1)
typedef long long ll;
int n;
map<int,ll>f,val;

ll cal(int x)
{
    if (x>n) return 0;
    if (f.count(x)) return f[x];
    int t=x,sl=0,sr=0;
    while(l(t)<=n)
    {
        sl++;
        t=l(t);
    }
    t=x;
    while(r(t)<=n)
    {
        sr++;
        t=r(t);
    }
    if (sl!=sr) t=n;
    ll ans=0;
    while(t>=x)
    {
        ans+=t;
        t>>=1;
    }
    return ans;
}
void update(int x,int y)
{
    val[x]=y;
    while(x)
    {
        f[x]=max(cal(l(x)),cal(r(x))) +(val.count(x)?val[x]:x);
        x>>=1;
    }
}
ll query(int x)
{
    ll ans=cal(l(x))+cal(r(x))+(val.count(x)?val[x]:x);
    ll now=cal(x);
    while(x>>1)
    {
        bool flag=x&1;
        x>>=1;
        now+=(val.count(x)?val[x]:x);
        if (flag) ans=max(ans,now+cal(l(x)));
        else ans=max(ans,now+cal(r(x)));
    }
    return ans;
}
int main()
{
    char s[10];
    int m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        f.clear();val.clear();
        int x,y;
        while(m--)
        {
            scanf("%s",s);
            if (s[0]=='q')
            {
                scanf("%d",&x);
                printf("%lld\n",query(x));
            }
            else
            {
                scanf("%d%d",&x,&y);
                update(x,y);
            }
        }
    }
    return 0;
}

  

posted @ 2017-08-23 17:14  BK_201  阅读(109)  评论(0编辑  收藏  举报