【OI】指针线段树&指针

对于线段树,我们一般需要n*4的空间去存储线段树,然后有一种玄学操作是用指针来实现线段树。

#include <inttypes.h>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
#define debug(x) std::cout<< #x << " = " << std::endl;

typedef long long int int_t;

using std::cin;
using std::cout;
using std::endl;

struct Node{
    
    Node *left,*right;
    int_t value;
    int begin,end;
    int mark;
    Node(int begin, int end) {
        this->begin = begin;
        this->end = end;
        left = right = NULL;
        mark = 0; 
    }
    
    void add(int_t val) {
        this->value += (end - begin + 1) * val;
        mark += val;
    }
    
    void maintain() {
        if(begin != end) {
            this->value = left -> value + right->value;
            
        }
        
        
    }
    
    void pushDown(){
        if (mark) {
            
            if(begin!= end) {
                left -> add(mark);
                right -> add(mark);
                
            }
            mark = 0;
        }
    }
    
    int_t query (int begin,int end){
        if(end < this->begin || begin > this->end) return 0;
        if(this->begin >= begin && this->end <= end) return this->value;
        this->pushDown();
        return left->query(begin,end) + right->query(begin, end) ;    
     
     }
     
     void add(int begin,int end,int_t val){
         if(end < this->begin || begin > this->end) return;
         if(this->begin >= begin && this->end <= end) {
             this->add(val);
             return ;
         }
         this->pushDown();
         left->add(begin,end,val);
         right->add(begin,end,val);
         this->maintain();
     }
    
    
};
char buf[400010*sizeof(Node)];
int used = 0;

void* allocate() { return (++used) * sizeof(Node) + buf;}

const int MaxN = 200010;
Node* tree;
int_t a[MaxN];
int n,m;

Node* build(int begin,int end){
    int mid = (begin + end)/2;
    
    Node* node = new(allocate()) Node(begin,end);
    if(begin != end){
        node->left = build(begin ,mid);
        node->right = build(mid+1,end);
        
        
    }
    
    else if(begin == end){
        node->value = a[begin];
    }
    
    node->maintain();
    return node;
}




int main(){
    scanf("%d%d",&n,&m);
    
    for(int i = 1; i <= n; i++){
        scanf("%lld",&a[i]);
    }
    
    tree = build(1,n);
    
    
    for(int i = 1; i <= m; i++){
        int opt,x,y;
        int_t k;
        scanf("%d",&opt);
        if(opt == 1){
            scanf("%d%d%lld",&x,&y,&k);
            tree->add(x,y,k);
            
        }
        else
        {
            scanf("%d%d",&x,&y);
            
            printf("%lld\n",tree->query(x,y));
        }
    }
    
    return 0;
}
Code

接着这个代码说一下指针:

声明指针的方法是 type *x;

例如 int* a;

这样就是声明了一个int类型的指针,没有指向任何的内存。

然后,可以使用 int* a = NULL; 来初始化它,这时候它是一个空指针,一旦对它试图对它操作就会RE,比如 int* a = NULL;

指针本质上一个存贮8比特地址的整形变量,所以应该使用取地址符&来给指针赋值:

int c;

int *a = &c;

我们要通过指针给原本元素赋值:

int c = 0;

int *a = &c;

*a = 5;

这时输出c的值为5

另一种写法是引用,相当于给了某个变量另一个名字,本质仍然是存储地址。

int c = 0;

int &a = c;

a = 5;

 与上面的写法是一样的效果。

指针不一定要指向某个变量,可以直接指向某个内存空间。

例如,我声明了一个结构体 struct custom{int a,b;};

然后,我们就可以使用指针指向内存中一个custom类型的内存,例如 custom* cs = new custom;

通过new关键字为这个指针创建一块内存,这个指针就指向它。

但是,如果想访问这个结构体的成员,则不同于原来的 "."访问,需要用 "->"来访问成员。

例如, cs->a = 0; 这样就算是给这个指针指向的结构体内存的a成员赋值为0。

但是,new是系统自动为其分配内存,比较慢,所以我们就可以创建一块内存池: char buf[400010*sizeof(custom)];

然后,用一个变量记录已经使用了内存池中的多少内存:int used = 0;

定义向这个内存池分配内存的函数:void* allocate() { return (++used) * sizeof(custom) + buf;}

used每次加1,记录已经使用了used个大小为sizeof(custom)的内存,然后加号后面是创建的内存池。

于是就可以使用这个内存池来分配内存:

custom *cs;

cs = new(allocate()) custom;

类型后面可以跟上构造函数,假设我们的custom有这样的构造函数:

custom(int a,int b){this->a = a;this->b = b;}

于是分配内存时就可以这样写:cs = new(allocate()) custom(1,2);

猜你喜欢

转载自www.cnblogs.com/dudujerry/p/10422864.html