kuangbin line segment tree-HDU-1166 enemy troops formation (line segment tree single point modification template question)

kuangbin line segment tree-HDU-1166 enemy troops formation (line segment tree single point modification template question)

General question sheet week 3 [kuangbin takes you to fly] Question sheet minimum spanning tree + line segment tree Click here ~~
https://blog.csdn.net/m0_46272108/article/details/108980362

Country C’s enemy, Country A, is conducting military exercises during this period, so country C spy leader Derek and his subordinate Tidy are busy again. Country A has arranged N engineering camps along the coastline. Derek and Tidy's task is to monitor the activities of these engineering camps. Due to some advanced monitoring methods, the number of people in each engineering camp is clear to country C. The number of people in each engineering camp may change, and it may increase or decrease a number of manpower, but these cannot escape C. State surveillance.
The CIA wants to study the enemy's tactics for the exercise, so Tidy must report to Derek at any time how many people are in a certain continuous engineering camp. For example, Derek asks: "Tidy, immediately report how many people there are from the third camp to the tenth camp. !" Tidy will start counting and reporting the total number of people in this segment right away. However, the number of enemy camps often changes, and Derek asks different segments each time, so Tidy has to count one by one camp each time, and quickly becomes exhausted. Derek calculates Tidy faster. More and more dissatisfied: "You fat guy, it's so slow, I'll fire you!" Tidy thought, "You can count it yourself. This is really tiring work! I can't wait for you to fire me! "In desperation, Tidy had to call Windbreaker, a computer expert, for help. Windbreaker said: "Deadly fat boy, I asked you to do more acm questions and read more algorithm books. Now you have the bitter fruit!" Tidy said: " I got it wrong..." But Windbreaker has hung up. Tidy is very distressed, he will really fall apart, clever reader, can you write a program to help him complete this work? But if your program is not efficient enough, Tidy will still be scolded by Derek.

Input

An integer T in the first line indicates that there are T groups of data.
The first row of each group of data is a positive integer N (N <= 50000) N (N<=50000)NN<=5 0 0 0 0 ) , which means that the enemy has N engineer camps, followed by N positive integers, the i-th positive integerai a_iaiRepresents ai a_i at the beginning of the i-th engineer campai 个人 ( 1 < = a i < = 50 ) (1<=ai<=50) 1<=to i<=5 0 ) .
There is a command on each line in the next, the command has 4 forms:
(1) Add ij, i and j are positive integers, which means that j individuals will be added to the i-th camp (j does not exceed 30)
(2) Sub ij ,i and j It is a positive integer, which means that the i-th camp reduces j individuals (j does not exceed 30);
(3) Query ij, i and j are positive integers, i <= j, which means the total number of people who inquired from the i-th camp to the j-th camp;
(4) End means end, this command appears at the end of each group of data;
each group of data has a maximum of 40,000 commands

Output

For the i-th group of data, first output "Case i:" and press Enter.
For each Query query, output an integer and press Enter to indicate the total number of people in the query segment. This number is kept within int.

Sample Input

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End 

Sample Output

Case 1:
6
33
59

You can understand the single-point modification of the line segment tree (and the code has a detailed explanation)
. For the single-point modification of the line segment tree, you can check this article (there are template questions and detailed graphic explanations):
Knowledge points about the line segment tree: https:// blog.csdn.net/m0_46272108/article/details/108955623

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<algorithm>

#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
//#define int ll
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
    
    
	int w = 1, s = 0;
	char ch = getchar();
	while (ch < '0' || ch>'9') {
    
     if (ch == '-') w = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') {
    
     s = s * 10 + ch - '0';    ch = getchar(); }
	return s * w;
//最大公约数
}int gcd(int x,int y) {
    
    
    if(x<y) swap(x,y);//很多人会遗忘,大数在前小数在后
    //递归终止条件千万不要漏了,辗转相除法
    return x % y ? gcd(y, x % y) : y;
}
int lcm(int x,int y)//计算x和y的最小公倍数
{
    
    
    return x * y / gcd(x, y);//使用公式
}
//------------------------ 以上是我常用模板与刷题几乎无关 ------------------------//
const int N = 50010;
int num[N * 4];	//存储每一个工兵营的人数

struct Node{
    
    
    int l, r;//左端点,右端点
    int val;//区间[l, r]的最大值
}tr[N << 2];


//由子节点的信息来计算父节点的信息
void pushup(int cur){
    
    
    //父节点是两个子节点的和,一直往上传值,就能使根节点是所有人的个数
    tr[cur].val = tr[cur << 1].val + tr[cur << 1 | 1].val;
}

//cur代表当前节点,
void build(int cur, int l, int r){
    
    
    
    //建树的初始值
    tr[cur].l = l, tr[cur].r = r, tr[cur].val = 0;
    //如果已经是叶结点return
    if(l == r) {
    
    
        tr[cur].val = num[l];//如果到达叶节点就把人数赋给该节点
        return;
    }
        
    //否则求一下当前区间的中点
    int mid = l + r >> 1;
    //递归建立左边区间
    build(cur << 1, l, mid);
    //递归建立右边区间
    build(cur << 1 | 1, mid + 1, r);
    
    //将子节点的人数进行汇总,给父节点
    pushup(cur);
}

//[l, r]查询区间   cur代表当前线段树里面的端点。
int query(int cur, int ql, int qr)  {
    
    
    int l = tr[cur].l, r = tr[cur].r;
    //①情况[TL,TR] ? [L,R]
    //树中节点,已经被完全包含在[l, r]中了。
    if(ql <= l && qr >= r)  
        return tr[cur].val;

    int mid = l + r >> 1;
    int val = 0;
    
    //判断与左边有交集
    if (ql <= mid) {
    
    
        val += query(cur << 1, ql, qr);//求和
    }
        
    
    //这里为什么是 qr > mid,因为划分的区间是[l, mid][mid + 1, r],所以要用>而不能=
    //判断与右边有交集
    if (qr > mid) {
    
    
        val += query(cur << 1 | 1, ql, qr);//求和
    }
    //返回结果
    return val;
}

//cur代表当前线段树里面的端点。tar代表要修改的位置,即目标位置
void modify(int cur, int tar, int val) {
    
    
    
    int l = tr[cur].l, r = tr[cur].r;
    //如果当前节点就是叶节点,那么直接修改就可以了
    if (l == r) {
    
    
        tr[cur].val = tr[cur].val + val;
        return;
    }
    int mid = l + r >> 1;
    if (tar <= mid) {
    
    
        modify (cur << 1, tar, val);
    } else {
    
    
        modify (cur << 1 | 1, tar, val);
    }
    //递归完之后,要更新到父节点。
    //pushup就是更新父节点的信息
    pushup(cur);    
}

int main()
{
    
    
    int t = read();
    for(int i = 1; i <= t; i++)
    {
    
    
        int n = read();
        for(int j = 1; j <= n; j++) 
            num[j] = read();
        //建树
        build(1, 1, n);
        int flag = 1;
        while (1) {
    
    
            string str;
            cin >> str;
            //Case 1:
            if (flag) {
    
    
                printf("Case %d:\n", i);
                flag = 0;
            }
            //询问
            if (str == "Query") {
    
    
                int ql = read(), qr = read();
                printf("%d\n", query(1, ql, qr));
            }
            //添加
            if (str == "Add") {
    
    
                int c = read(), m = read();
                modify(1, c, m);
            }
            //减去
            if (str == "Sub") {
    
    
                int c = read(), m = read();
                modify(1, c, -m);
            }
            //结束
            if (str == "End")
                break;
        }
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/m0_46272108/article/details/108961955