2017多校第9场 HDU 6161 Big binary tree 思维,类似字典树

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

题意:

题目是给一棵完全二叉树,从上到下从左到右给每个节点标号,每个点有权值,初始权值为其标号,然后有两种操作:
1、把u点权值改为x
2、查询所有经过u点的路径中,路径上的点权和最大。
节点有n个,修改有m个,n<=1e8 ,m<= 1e5

解法:现场队友过的,orz,来自队友的思路。

我们首先对于一个点,如果没有访问我们不把它建出来,相反访问了就把它建出来,这个题的最小的子问题就是计算一个节点的答案怎么算,我们直接往右子树怼?显然并不全是,我们发现从n上来这一条链上的节点的答案并不一定是一直往右走,所以我们特殊处理这条链就可以 了。这就解决了最小的子问题,用log2n的复杂度算出了每个节点的答案,接下来就是更新和查询,更新的话,我们先更新这个节点,然后从这个节点到1这条链上的点都要更新,我们直接更新上去即可,对于查询来说,和更新一样我们只需要关心这个点所在的链上的信息,所以我们直接往上跑并且查询,这里查询就要贪心一下,如果有左儿子就累加上靠右儿子的答案,否则累加左儿子的答案,这里画个图模拟一下即可,这些点的信息可以用unorder_map和unorder_set来方便的维护,复杂度O(logn*logn)。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
unordered_map<int,pair<LL,LL> >mp;//u点,左儿子,右儿子
unordered_map<int,LL>now;//现在这个u节点的值
unordered_set<int>st;//题解上说的那条特殊链
int n,m;
LL cal(int u){
    if(u>n) return 0;
    if(mp.count(u)){
        auto p=mp[u];
        return max(p.first,p.second);
    }
    if(st.count(u)){
        int v1=u*2;
        int v2=u*2+1;
        if(st.count(v1)) return u+cal(v1);
        else return u+cal(v2);
    }
    return u+cal(u*2+1);
}
void init(){
    mp.clear();
    st.clear();
    int t=n;
    do{
        st.insert(t);
        t/=2;
    }while(t);
}
void update(int u, LL val){
    if(mp.count(u)==0){
        mp.emplace(u, make_pair(cal(u*2)+u,cal(u*2+1)+u));
        now[u]=u;
    }
    auto &p=mp[u];
    p.first+=val-now[u];
    p.second+=val-now[u];
    now[u]=val;
    int t=u;
    u/=2;
    while(u){
        if(mp.count(u)==0){
            mp.emplace(u, make_pair(cal(u*2)+u,cal(u*2+1)+u));
            now[u]=u;
        }
        else{
            auto &p2=mp[u];
            if(u*2==t){
                p2.first=now[u]+cal(u*2);
            }
            else{
                p2.second=now[u]+cal(u*2+1);
            }
        }
        u/=2;
        t/=2;
    }
}
LL query(int u){
    LL ans=0;
    if(mp.count(u)==0){
        mp.emplace(u,make_pair(u+cal(u*2),u+cal(u*2+1)));
        now[u]=u;
    }
    auto &p=mp[u];
    ans = p.first+p.second-now[u];
    LL len = max(p.first, p.second);
    int t=u;
    u/=2;
    while(u){
        if(mp.count(u)==0){
            mp.emplace(u,make_pair(cal(u*2)+u,cal(u*2+1)+u));
            now[u]=u;
        }
        auto &p=mp[u];
        if(u*2==t){
            ans=max(ans,p.second+len);
        }
        else{
            ans=max(ans,p.first+len);
        }
        len+=now[u];
        t/=2;
        u/=2;
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d", &n,&m))
    {
        init();
        for(int i=1; i<=m; i++){
            char op[10];
            scanf("%s", op);
            if(op[0] == 'q'){
                int x;
                scanf("%d", &x);
                printf("%lld
", query(x));
            }
            else{
                int x;
                LL y;
                scanf("%d%lld", &x,&y);
                update(x,y);
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/spfa/p/7418907.html