fzu_1921栀子花开 线段树_单点更新

Problem 1921 栀子花开

Accept: 234    Submit: 790
Time Limit: 1000 mSec    Memory Limit : 32768 KB

Problem Description

这是一个栀子花开的季节,也是一个离别的季节,四年一千多个日日夜夜,那校园的角角落落,留下了我们沉思的身影;那上百次的成绩排名表,印证了我们深深浅浅不断进步的轨迹,但是这些进步都离不开老师的谆谆教诲。

作为计算机系的学生,算法与数据结构是必修的主干课程,因此课程的每个老师都很关心每个学生的学习情况,每天下课老师都会给某个学生进行课外辅导。首先,老师会给每个学生一个能力评定分数,如果有学生要求老师给他辅导,那老师就会专门给该同学进行课外辅导,如果没有学生要求,老师就会给评定分数最低的同学课外辅导。老师给学生辅导后,学生的能力都会有所增长,然而不同的学生增长的情况都不同。老师想知道为学生课外辅导若干天后,全班的最低分学生的编号和分数。

Input

首先第一行为T,表示有T组数据。接下来为每组数据的结构:

第一行有一个数字n,表示有n个学生,编号从1到n。(1 <= n <= 10000)。

接下来一行有n个数,分别是编号从1到n的学生的初始能力水平xi,(1 <= xi <= 1000)。

接下来有一行有一个数m表示老师给学生课外辅导了m天(1 <= m <= 100000)。

接下来m行,每行两个数(ai bi),表示老师在第i天给编号为ai同学补课,编号为ai的同学能力提高了bi(0 <= ai <= n,1 <= bi <= 1000)。如果ai为0,则表示老师今天给能力最差的学生辅导。如果最低分同时有多个学生,就给编号小的学生补课。

Output

对于每组数据输出一行先输出组数(从1开始),接着最后输出经过m天后,全班的最低分学生的编号和分数。

Sample Input

1 3 10 20 30 3 0 100 3 10 0 40

Sample Output

Case 1: 3 40

Hint

上面的数据,各个学生的能力增长情况如下:

第一天后:110 20 30

第二天后:110 20 40

第三天后:110 60 40

 

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define mem0(a) memset(a,0,sizeof(a))
const int maxn = 10000+10;
int a[maxn<<2];
void Getmin(int cur){
    a[cur]=min(a[cur<<1],a[cur<<1|1]);
}
void build(int l,int r,int cur){
    if(l == r){
        scanf("%d",&a[cur]);
        return ;
    }
    int mid = (l + r) >> 1;
    build(l,mid,cur<<1);
    build(mid+1,r,cur<<1|1);
    Getmin(cur);
}
void update1(int k,int v,int l,int r,int cur){//第k结点增加v
    if(l == r){
        a[cur]+= v;
        return ;
    }
    int mid = (l + r )>>1;
    if( k <= mid)
        update1(k,v,l,mid,cur<<1);
    else
        update1(k,v,mid+1,r,cur<<1|1);
    Getmin(cur);
}
void update2(int v,int l,int r,int cur){//找出最小的结点
    if(l == r){
//        printf("%d---%d  %d\n",l,a[cur],cur);
        a[cur]+= v;
        return ;
    }
    int mid = (l + r )>>1;//因为根结点保存的是两个子结点的较小值
    if( a[cur] == a[cur<<1])//当最小值在左儿子上时
        update2(v,l,mid,cur<<1);//更新左儿子
    else                        //同理最小值在右儿子上
        update2(v,mid+1,r,cur<<1|1);
    Getmin(cur);
}
void query(int l,int r,int cur){
    if(l==r) {
        printf("%d %d\n",l,a[cur]) ;//l就是分数最小的编号,线段树子叶都看做是编号
        return ;
    }
    int mid = ( l + r )>>1 ;
    if(a[cur] == a[cur<<1])
        query(l,mid,cur<<1);
    else
        query(mid+1,r,cur<<1|1);
}
int main()
{
    int n,T,m,t=1;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        build(1,n,1);
//          printf("&&%d %d %d %d %d\n",a[1],a[2],a[4],a[5],a[3]);
        scanf("%d",&m);
        while(m--){
            int x,y;
            scanf("%d%d",&x,&y);
            if(x != 0){
                update1(x,y,1,n,1);
//                printf("~~%d %d %d\n",a[4],a[5],a[3]);
            }
            else{
                update2(y,1,n,1);
//                printf("!!%d %d %d\n",a[4],a[5],a[3]);
            }
        }
        printf("Case %d: ",t++);
        query(1,n,1);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值