hdu 6161

来源:互联网 发布:怎样金融网络投资 编辑:程序博客网 时间:2024/05/29 16:47
Problem Description

You are given a complete binary tree with n nodes. The root node is numbered 1, and node x's father node is x/2. At the beginning, node x has a value of exactly x. We define the value of a path as the sum of all nodes it passes(including two ends, or one if the path only has one node). Now there are two kinds of operations:
1.  change u x Set node u's value as x(1≤u≤n;1≤x≤10^10)
2.  query u Query the max value of all paths which passes node u.
 

Input
There are multiple cases.
For each case:
The first line contains two integers n,m(1≤n≤10^8,1≤m≤10^5), which represent the size of the tree and the number of operations, respectively.
Then m lines follows. Each line is an operation with syntax described above.
 

Output
For each query operation, output an integer in one line, indicating the max value of all paths which passes the specific node.
 

Sample Input
6 13query 1query 2query 3query 4query 5query 6change 6 1query 1query 2query 3query 4query 5query 6
 

Sample Output
171717161717121212111212
 

Source
2017 Multi-University Training Contest - Team 9

题意:题中给出一颗完全二叉树,从上到下从左到右标号分别为1~n,并且每个节点的初始值=标号,然后有两种操作

1.query x
询问所有经过x节点的路径中,路径权值总和最大值
2.change x y
将节点x的权值改为y

思路:首先我们要清楚这种路径存在的形式有两种

1.

2.



画工有点不到家@@

我们需要解决这几步
1.计算一条以x为根节点的的向下延伸的最长链
如果down[x]已经出现过,直接就是结果,如果没出现过那么他的子树中的节点全是初始值的节点
此时有两种情况
(1)子树是一颗满二叉树,这样的话就一直走右节点就可以了
(2)子树是只是一颗完全二叉树,不是满二叉树,这样的话从n节点一直找父亲节点就可以了
2.计算x到x的某一祖宗节点的路径的权值和

ac代码:
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<map>#define ll long longusing namespace std;int n,m;char in[10];map<int,ll> val,down;ll cal(int x)  //计算从x结点向下走可以取得的最大和{    if(x>n) return 0;    if(down.count(x)) return down[x];  //如果在down中出现过,直接返回    else  //说明以x为根的树中所有结点都没有被修改过,尽量向右走    {        ll res=0;        int leftlevel=0,rightlevel=0;        int compare=x;        while((compare<<1)<=n)        {            compare<<=1;            leftlevel++;        }        compare=x;        while((compare<<1|1)<=n)        {            compare=(compare<<1|1);            rightlevel++;        }        if(leftlevel!=rightlevel) compare=n;        while(compare>=x)        {            res+=compare;            compare>>=1;        }        return res;    }}ll query(int x){    //初始路径设为以x为根,分别向左右两个方向走    ll res=cal(x<<1)+cal(x<<1|1)+(val.count(x)?val[x]:x);    ll sti=cal(x); //记录向上走的路径上的结点之和    //答案也有可能是以x的某个祖先为根,分别向两边走的路径,所以一层一层向上递推    while(x>>1)    {        sti+=val.count(x>>1)?val[x>>1]:(x>>1);        if(x&1)//从右儿子上来        {            x>>=1;            res=max(res,sti+cal(x<<1));        }        else//从左儿子上来        {            x>>=1;            res=max(res,sti+cal(x<<1|1));        }    }    return res;}void change(int pos,ll value){    val[pos]=value;    down[pos]=max(cal(pos<<1),cal(pos<<1|1))+val[pos];    while(pos>>1)//改变某个点的值只会影响它的祖先    {        pos>>=1;        down[pos]=max(cal(pos<<1),cal(pos<<1|1))+(val.count(pos)?val[pos]:pos);    }}int main(void){    int a;    ll b;    while(scanf("%d%d",&n,&m)!=EOF)    {        val.clear();        down.clear();        for(int i=1;i<=m;++i)        {            scanf("%s",in);            if(in[0]=='q')            {                scanf("%d",&a);                printf("%I64d\n",query(a));            }            else            {                scanf("%d%I64d",&a,&b);                change(a,b);            }        }    }}


原创粉丝点击