hrbust 哈理工oj 1752Page Rank【线段树好题】

Page Rank
Time Limit: 1000 MSMemory Limit: 65536 K
Total Submit: 85(30 users)Total Accepted: 40(23 users)Rating: Special Judge: No
Description

There are n webpages, each of which has its respective page rank. The content is constantly updated and page rank is also constantly changing. Can you immediately find the page with highest weight?

Note: We set the page numbers from 1 to n.

Input

There are multiple test cases, process to the end of file.

For each test case:

Line 1: This line contains an integer n, indicating the number of pages.

Line 2: This line contains n integer, pr1, pr2, pr3, ..., prn, representing the page rank of each page.

Line 3: This line contains an integer q, indicating the number of operations.

Line 4..q+3: Each line indicating an operation.

There are two operation formats:

C i pr : change ith page's page rank to pr.

Q : query a page with the highest page rank, output the page's number and its page rank.

Limits

1<=n<=100,000

1<=q<=200,000

0<=pr<=1,000,000,000

Output

For each case:

Each "Q" query outputs a line containing the page number and page rank of the page of the highest page rank. If there is more than one page which has the highest page rank, output the page with largest number.

After each test case, output a blank line.

Sample Input
5
30 9 0 20 5 
6
C 1 19
C 3 22
C 3 4
Q
C 4 12
Q
5
13 10 20 7 7 
7
C 4 22
C 4 21
C 4 11
C 3 10
C 5 15
C 2 17
Q
Sample Output
4 20
1 19

2 17

这题的数据还是很屌的,我的思路实力TLE、原因是单点查询找的位子,不如大牛代码里边的区间找值定位子的方法好、所以这里直接说大牛的代码是如何实现的吧:

首先是build:

void pushup(int rt)
{
    if (tree[rt<<1] > tree[rt<<1|1])//位子跟着值的变化而变化,这里也可以写成结构体,看起来方便一点。
    {
        tree[rt] = tree[rt<<1];
        posn[rt] = posn[rt<<1];
    }
    else
    {
        tree[rt] = tree[rt<<1|1];
        posn[rt] = posn[rt<<1|1];
    }
}
void build(int l, int r, int rt)//大同小异的部分,
{
    if (l == r)
    {
        scanf("%d", &tree[rt]);
        posn[rt] = l;
    }
    else
    {
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        pushup(rt);
    }
}
然后是update、

void update(int p, int val, int l, int r, int rt)
{
    if (l == r)
    {
        tree[rt] = val;
    }
    else
    {
        int m = (l + r) >> 1;
        if (p <= m)
        {
            update(p, val, lson);
        }
        else
        {
            update(p, val, rson);
        }
        pushup(rt);
    }
}
关键部分是query操作:

int query(int L, int R, int l, int r, int rt, int *pos)
{
    if (L <= l && r <= R)//区间
    {
        *pos = posn[rt];
        return tree[rt];
    }
    else
    {
        int m = (l + r) >> 1;
        int ret1 = INT_MIN;
        int ret2 = INT_MIN;
        int pa, pb;
        int *pos1 = &pa;
        int *pos2 = &pb;
        if (L <= m)
        {
            ret1 = query(L, R,  lson, pos1);//ret1表示这部分区间的最大值,同时在这部分的query过程中,找到了pos1,表示这部分区间最大值的位子
        }
        if (R > m)
        {
            ret2 = query(L, R, rson, pos2);//ret2表示这部分区间的最大值,
        }
        if (ret1 > ret2)//如果ret1>ret2,无疑让pos变成pa
        {
            *pos = pa;
        }
        else//这里是关键,题目中说,如果有值相同的情况下,要输出大的位子、我们知道,rson的number总是比lson的number大,所以这里保证了题目的要求。
        {
            *pos = pb;
            ret1 = ret2;
        }
        return ret1;//return最大值、
    }
}

最后上完整的AC代码:

#include<cstdio>
#include<climits>
#include<algorithm>

using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, (rt<<1)|1

int tree[111111<<2];
int posn[111111<<2];
void pushup(int rt)
{
    if (tree[rt<<1] > tree[rt<<1|1])
    {
        tree[rt] = tree[rt<<1];
        posn[rt] = posn[rt<<1];
    }
    else
    {
        tree[rt] = tree[rt<<1|1];
        posn[rt] = posn[rt<<1|1];
    }
}
void build(int l, int r, int rt)
{
    if (l == r)
    {
        scanf("%d", &tree[rt]);
        posn[rt] = l;
    }
    else
    {
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        pushup(rt);
    }
}
void update(int p, int val, int l, int r, int rt)
{
    if (l == r)
    {
        tree[rt] = val;
    }
    else
    {
        int m = (l + r) >> 1;
        if (p <= m)
        {
            update(p, val, lson);
        }
        else
        {
            update(p, val, rson);
        }
        pushup(rt);
    }
}
int query(int L, int R, int l, int r, int rt, int *pos)
{
    if (L <= l && r <= R)
    {
        *pos = posn[rt];
        return tree[rt];
    }
    else
    {
        int m = (l + r) >> 1;
        int ret1 = INT_MIN;
        int ret2 = INT_MIN;
        int pa, pb;
        int *pos1 = &pa;
        int *pos2 = &pb;
        if (L <= m)
        {
            ret1 = query(L, R,  lson, pos1);
        }
        if (R > m)
        {
            ret2 = query(L, R, rson, pos2);
        }
        if (ret1 > ret2)
        {
            *pos = pa;
        }
        else//这里保证最大位子优先、
        {
            *pos = pb;
            ret1 = ret2;
        }
        return ret1;
    }
}
int main(void)
{
    int n, m;

    while (scanf("%d", &n) != EOF)
    {
        build(1, n, 1);

        scanf("%d", &m);
        char op[2];
        int a, b;
        while (m--)
        {
            scanf("%s", op);
            if (op[0] == 'Q')
            {
                int pos;
                printf("%d %d\n", pos, query(1, n, 1, n, 1, &pos));
            }
            else
            {
                scanf("%d%d", &a, &b);
                update(a, b, 1, n, 1);
            }
        }
        printf("\n");
    }

    return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值