nyoj116士兵杀敌(二)线段树单点更新

士兵杀敌(二)

时间限制:1000 ms  |  内存限制:65535 KB

难度:5

描述

南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的。

小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧。

南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新增的杀敌数。

输入
只有一组测试数据

第一行是两个整数N,M,其中N表示士兵的个数(1<N<1000000),M表示指令的条数。(1<M<100000)

随后的一行是N个整数,ai表示第i号士兵杀敌数目。(0<=ai<=100)

随后的M行每行是一条指令,这条指令包含了一个字符串和两个整数,首先是一个字符串,如果是字符串QUERY则表示南将军进行了查询操作,后面的两个整数m,n,表示查询的起始与终止士兵编号;如果是字符串ADD则后面跟的两个整数I,A(1<=I<=N,1<=A<=100),表示第I个士兵新增杀敌数为A.

输出
对于每次查询,输出一个整数R表示第m号士兵到第n号士兵的总杀敌数,每组输出占一行
样例输入
5 6
1 2 3 4 5
QUERY 1 3
ADD 1 2
QUERY 1 3
ADD 2 3
QUERY 1 2
QUERY 1 5
样例输出
6
8
8
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 1000001
#define inf 0x3f3f3f3f
int ll[maxn<<2],rr[maxn<<2],sum[maxn<<2];
int a[maxn];
void build(int l,int r,int i){
    ll[i]=l;
    rr[i]=r;
    if(ll[i]==rr[i]){
        sum[i]=a[l];
        return ;
    }
    int m=(l+r)>>1,ls=i<<1,rs=ls|1;
    build(l,m,ls);
    build(m+1,r,rs);
    sum[i]=sum[ls]+sum[rs];
}
void update(int k,int v,int i){
    if(ll[i]==rr[i]){
        sum[i]+=v;
        return;
    }
    int m=(ll[i]+rr[i])>>1,ls=i<<1,rs=ls|1;
    if(k<=m){
        update(k,v,ls);
    }
    else{
        update(k,v,rs);
    }
    sum[i]=sum[ls]+sum[rs];
}
int finds(int l,int r,int i){
    if(ll[i]==l&&rr[i]==r){
        return sum[i];
    }
    int m=(ll[i]+rr[i])>>1,ls=i<<1,rs=ls|1;
    if(r<=m){
        return finds(l,r,ls);
    }
    else if(l>m){
        return finds(l,r,rs);
    }
    else{
        return finds(l,m,ls)+finds(m+1,r,rs);
    }

}

int main()
{
    int n,m;
    int x,y;
    int A,I;
    char q[10];
    freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        build(1,n,1);
        for(int i=1;i<=m;i++){
            scanf("%s",q);
            if(!strcmp(q,"QUERY")){
                scanf("%d%d",&x,&y);
                printf("%d\n",finds(x,y,1));
            }
            else {
                scanf("%d%d",&A,&I);
                update(A,I,1);
            }
        }
    }
}

时间: 2024-10-24 16:43:08

nyoj116士兵杀敌(二)线段树单点更新的相关文章

NYOJ 116 士兵杀敌(二)【线段树 单点更新】

题意:题意很清楚: 策略:如题. 这道题就是简单的线段树应用,据说还可以用树状数组来做,等我学了之后在说吧. 代码: #include<stdio.h> #include<string.h> #define LC l, m, rt<<1 #define RC m+1, r, rt<<1|1 #define LL long long #define MAXN 1000000 LL sum[MAXN<<2]; void PushUp(int rt)

hdu 3308 线段树单点更新 区间合并

http://acm.hdu.edu.cn/showproblem.php?pid=3308 学到两点: 1.以区间端点为开始/结束的最长......似乎在Dp也常用这种思想 2.分类的时候,明确标准逐层分类,思维格式: 条件一成立: { 条件二成立: { } else { } } else { 条件二成立: { } else { } } 上面的这种方式很清晰,如果直接想到那种情况iif(条件一 &条件二)就写,很容易出错而且把自己搞乱,或者情况不全,,,我就因为这WA了几次 3.WA了之后 ,

POJ训练计划2828_Buy Tickets(线段树/单点更新)

解题报告 题意: 插队完的顺序. 思路: 倒着处理数据,第i个人占据第j=pos[i]+1个的空位. 线段树维护区间空位信息. #include <iostream> #include <cstdio> #include <cstring> using namespace std; struct node { int x,v; } num[201000]; int sum[1000000],ans[201000]; void cbtree(int rt,int l,in

HDU2852_KiKi&#39;s K-Number(线段树/单点更新)

解题报告 题目传送门 题意: 意思很好理解. 思路: 每次操作是100000次,数据大小100000,又是多组输入.普通模拟肯定不行. 线段树结点记录区间里存在数字的个数,加点删点操作就让该点个数+1,判断x存在就查询[1,x]区间的个数和[1,x-1]的个数. 求x之后第k大的数就先确定小于x的个数t,第t+k小的数就是要求的. #include <iostream> #include <cstdio> #include <cstring> using namespa

POJ3264_Balanced Lineup(线段树/单点更新)

解题报告 题意: 求区间内最大值和最小值的差值. 思路: 裸线段树,我的线段树第一发.区间最值. #include <iostream> #include <cstring> #include <cstdio> #define inf 99999999 #define LL long long using namespace std; LL minn[201000],maxx[201000]; void update(LL root,LL l,LL r,LL p,LL

HDU1166_敌兵布阵(线段树/单点更新)

解题报告 题意: 略 思路: 线段树单点增减和区间求和. #include <iostream> #include <cstring> #include <cstdio> #define LL long long using namespace std; int sum[201000]; void update(int root,int l,int r,int p,int v) { int mid=(l+r)/2; if(l==r)sum[root]+=v; else

HDU1754_I Hate It(线段树/单点更新)

解题报告 题意: 略 思路: 单点替换,区间最值 #include <iostream> #include <cstring> #include <cstdio> #define inf 99999999 using namespace std; int maxx[808000]; void update(int root,int l,int r,int p,int v) { int mid=(l+r)/2; if(l==r)maxx[root]=v; else if(

Uva 12299 RMQ with Shifts(线段树 + 单点更新 )

Uva 12299 RMQ with Shifts (线段树 + 单点更新) 题意: 对于给定的序列 x[i]给出一个操作 shift(a,b,c,d,e) 对应的是将 x[a]与x[b] x[b]与x[c] 这样相邻的两两交换For example, if A={6, 2, 4, 8, 5, 1, 4}then shift(2, 4, 5, 7) yields {6, 8, 4, 5, 4, 1, 2}. After that,shift(1, 2) yields {8, 6, 4, 5, 4

POJ2352_Stars(线段树/单点更新)

解题报告 题意: 坐标系中,求每颗星星的左下角有多少星星. 思路: 把横坐标看成区间,已知输入是先对y排序再对x排序,每次加一个点先查询该点x坐标的左端有多少点,再更新点. #include <iostream> #include <cstdio> #include <cstring> using namespace std; int sum[200000]; struct node { int x,y; } p[20000]; void push_up(int roo

HDU 1754 I Hate It (线段树 单点更新)

题目链接 中文题意,与上题类似. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <cstdlib> 6 #include <algorithm> 7 const int maxn = 200000+10; 8 using namespace std; 9 int a[maxn], n, m; 10