复习3-数据结构模板

1.线段树

 

#include <bits/stdc++.h>

using namespace std;

int n,p,a,b,m,x,y,ans;

struct node{
    int l,r,w,f;
}tree[100005];

void build(int l,int r,int o){
    tree[o].l = l,tree[o].r = r;
    if(tree[o].l == tree[o].r) {
        scanf("%d",&tree[o].w);
        return;
    }
    int mid = (l+r)/2;
    build(l,mid,o*2);
    build(mid+1,r,o*2+1);
    tree[o].w = tree[o*2].w + tree[o*2+1].w;
}

void pushdown(int o){
    tree[o*2].f += tree[o].f;
    tree[o*2+1].f += tree[o].f;
    tree[o*2].w += (tree[o*2].r-tree[o*2].l+1) * tree[o].f;
    tree[o*2+1].w += (tree[o*2+1].r-tree[o*2+1].l+1) * tree[o].f;
    tree[o].f = 0;
}

void change_point(int o){
    if(tree[o].l == tree[o].r){
        tree[o].w += y;
        return ;
    }
    if(tree[o].f) pushdown(o);
    int mid = (tree[o].l+tree[o].r)/2;
    if(x <= mid) change_point(o*2);
    else change_point(o*2+1);
    tree[o].w = tree[o*2].w + tree[o*2+1].w;
}

void query_point(int o){
    if(tree[o].l == tree[o].r){
        ans = tree[o].w;
        return ;
    }
    if(tree[o].f)pushdown(o);
    int mid = (tree[o].l + tree[o].r)/2;
    if(x <= mid) query_point(o*2);
    else query_point(o*2+1);
}

void query_interval(int o){
    if(tree[o].l >= a && tree[o].r <= b){
        ans += tree[o].w;
        return ;
    }
    if(tree[o].f)pushdown(o);
    int mid = (tree[o].l + tree[o].r)/2;
    if(a <= mid) query_interval(o*2);
    if(b > mid) query_interval(o*2+1);
}

void change_interval(int o){
    if(tree[o].l >= a && tree[o].r <= b){
        tree[o].w += (tree[o].r-tree[o].l+1) * y;
        tree[o].f += y;
        return;
    }
    if(tree[o].f)pushdown(o);
    int mid = (tree[o].l + tree[o].r)/2;
    if(a <= mid) change_interval(o*2);
    if(b > mid) change_interval(o*2+1);
    tree[o].w = tree[o*2].w + tree[o*2+1].w;
}

int main(){
    scanf("%d",&n);scanf("%d",&m);
    build(1,n,1);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&p);
        ans=0;
        
        if(p==2)
        {
            scanf("%d%d",&a,&b);
            query_interval(1);
            printf("%d\n",ans);
        }
        else
        {
             scanf("%d%d%d",&a,&b,&y);
             change_interval(1);
        }
    }
    return 0;
}
五种操作

 

 

 

2.树状数组

int lowbit(int x){
    return x & -x;
}

void add(int x,int y)
{
    for(;x <= n;x += lowbit(x)) c[x] += y;
}

int query(int x)
{
    int ans = 0;
    for(;x >= 1;x -= lowbit(x)) ans += c[x];
    return ans;
}
单点修改+区间求和
ll c0[MAXN], c1[MAXN];
  int lowbit(int x){
      return x & -x;
  }
  void add(ll *c, int x, ll k) {
    for(; x <= N; x += lowbit(x)) c[x] += k;
  }
  ll sum(ll *c, int x) { 
    ll r = 0; 
    for(;x >= 1; x -= lowbit(x)) r += c[x];
    return r;
  }
  void add(int l, int r, ll k) {
    add(c0, l, k); add(c0, r + 1, -k);
    add(c1, l, (l - 1) * k); add(c1, r + 1, -r * k);
  }
  ll sum(int l, int r) {
    return sum(c0, r) * r - sum(c1, r) - sum(c0, l - 1) * (l - 1) + sum(c1, l - 1);
  }
区间修改+区间求和

 

3.ST表

inline int query(int l,int r)
{
    int tmp = lg[r-l+1];
    return max(dp[l][tmp],dp[r-(1<<tmp)+1][tmp]);
}

inline void init()
{
    for(register int i = 1;i <= n;i++)
    dp[i][0] = a[i];
    for(register int j = 1;j < 21;j++)
    {
        for(register int i = 1;i+(1 << j-1) <= n;i++)
        {
            dp[i][j] = max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
        }
    }
    for(register int i = 2;i <= n;i++)
    lg[i] = lg[i >> 1]+1;
}

 

4.并查集

void init(int n){
    for(int i = 0;i < n;i++)
    {
        father[i] = i;
        high[i] = 0;
    }
}

int find(int x){
    if(father[x] == x) return x;
    else return father[x] = find(father[x]);
}

void uniue(int x,int y){
    x = find(x);
    y = find(y);
    if(x == y) return;
    
    if(high[x] < high[y]) father[x] = y;
    else {
        father[y] = x;
        if(high[x] == high[y]) high[x]++;
    }
}

bool same(int x,int y){
    return find(x) == find(y);
}
按秩合并

5.队列、栈

 

//数组实现
#include <cstdio>
#define MAXN 2000005
using namespace std;

struct Num{
    int index,x;//需要记录单调队列内每个数的入队时间(index)和大小(x)
};

int a[MAXN]; //原数组
Num q[MAXN]; //单调队列 

int main(void){
    int n,m; //n表示序列长度,m表示滑动窗口长度
    int front,back; //front,back分别表示队头、队尾位置
    //输入
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    //问题解决
    front=1;
    back=0;//初始化队头队尾位置,队头>队尾表示队空
    for (int i=1;i<=n;i++){
        //先输出数a[i]前的最小值
        if (front>back) //q空,即a[i]前没有元素
            printf("0\n");
        else { //否则判断队头是否需要出队并输出范围内的队头
            if (q[front].index+m<i) //队头已经超出滑动窗口范围
                front++; // 弹出队头
            printf("%d\n",q[front].x); //此时队一定非空(想想为什么)
        }
        while (front<=back && q[back].x>=a[i]) 
        //当队列非空时,不断弹出队尾比当前元素大的元素
            back--;
        back++;
        q[back].x=a[i];
        q[back].index=i;//将当前元素入队
        //注意:当前元素无论如何都会入队(想想为什么)
    }
    return 0;
}

//deque实现
#include <cstdio>
#include <queue> // 提供deque
#define MAXN 2000005
using namespace std;

struct Num{
    int index,x;//需要记录单调队列内每个数的入队时间(index)和大小(x)
};

int a[MAXN]; //原数组
deque<Num> q; //单调队列 

int main(void){
    int n,m; //n表示序列长度,m表示滑动窗口长度
    Num t;//保存当前元素
    //输入
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    //问题解决
    for (int i=1;i<=n;i++){
        //先输出数a[i]前的最小值
        if (q.empty()) //q空,即a[i]前没有元素
            printf("0\n");
        else { //否则判断队头是否需要出队并输出范围内的队头
            if (q.front().index+m<i) //队头已经超出滑动窗口范围
                q.pop_front(); // 弹出队头
            printf("%d\n",q.front().x); //此时队一定非空(想想为什么)
        }
        while ((!q.empty()) && q.back().x>=a[i]) 
        //当队列非空时,不断弹出队尾比当前元素大的元素
            q.pop_back();
        t.index=i;
        t.x=a[i];
        q.push_back(t);//将当前元素入队
        //注意:当前元素无论如何都会入队(想想为什么)
    }
    return 0;
}
单调队列

 

posted @ 2018-11-08 19:48  bryce02  阅读(153)  评论(0编辑  收藏  举报
Live2D