SPOJ TO THE MOON 主席树(有动态修改)

来源:互联网 发布:达内 训机构北京php 编辑:程序博客网 时间:2024/06/05 11:12

题目大意:

       题目大意:给定一些数字,有以下几个操作

       a、[L,R]区间的数字变化D的数值。并且时间向前推进

       b、询问某个时间的[L,R]区间的数字之和,这不花费时间

       c、回到X时间。


主席树带动态操作裸题。  但是也可以用主席树,不push版本


AC CODE: 300+M内存使用


#include <bits/stdc++.h>using namespace std;#define pr(x)x#define prln(x)x//#define pr(x)cout<< #x << " = " <<x<<" "//#define prln(x)cout<< #x << " = " <<x<<endlconst int maxn = 123456;const int maxnode = maxn * 100;int n, m;struct node  {      int lson, rson;      long long val;//区间权重      long long change;//区间修改值,为0表示没有需要传递的      int ver;}tree[maxnode];  int tail, root[maxn]; long long w[maxn];char inp[15];int ql, qr, qans, qver;  #define LSON tree[o].lson,L, M  #define RSON tree[o].rson, M + 1 , R  #define SELF o,L,R  #define lc tree[o].lson  #define rc tree[o].rson  void push_down(int o, int L, int R)//向下传递标记, o节点的val值不变{  if (tree[o].change && L < R)  {  if (tree[lc].ver != qver){tree[++tail] = tree[lc];tree[o].lson = tail;tree[lc].ver = qver;}if (tree[rc].ver != qver){tree[++tail] = tree[rc];tree[o].rson = tail;tree[rc].ver = qver;}tree[lc].change += tree[o].change;  tree[rc].change += tree[o].change;  tree[o].change = 0;  }  }  //更新o节点的val信息。那么就需要把儿子的信息汇总到o//要特别注意,儿子的懒人标记的信息和val信息汇总void maintain(int o, int L, int R) {  if (L < R)  {  int M = L+(R-L)/2;  tree[o].val = tree[lc].val + tree[rc].val + tree[lc].change * (M-L+1) + tree[rc].change * (R-M);  }  //L==R的情况,不包含的左右儿子,所以再query里询问到的节点,直接结合处理了}  void build(int o, int L, int R)  {  tree[o].change = 0;  tree[o].ver = 0;//一开始建树,建的是0号版本的if (L== R)  {  tree[o].val = w[L];  return ;  }  tree[o].lson = ++ tail;  tree[o].rson = ++ tail;  int M = L + (R - L) / 2;  build(LSON);  build(RSON);  maintain(SELF);}void insert(int &o, int L, int R){tree[++ tail] = tree[o];o = tail;tree[o].ver = qver;if (ql <= L && R <= qr){tree[o].change += qans;return;}push_down(SELF);int M = L + (R-L)/2;if (ql <= M)insert(LSON);else maintain(LSON);if (qr > M)insert(RSON);else maintain(RSON);maintain(SELF);}long long query(int o, int L, int R)  {  if (tree[o].ver != qver){tree[++tail] = tree[o];o = tail;tree[o].ver = qver;}if (ql <= L && R <= qr)  {  //返回的值需要考虑到懒人标记信息return tree[o].val + tree[o].change * (R-L+1);//因为根节点的传递标记一直都在  }  push_down(SELF);  int M = L + (R - L) / 2;  long long ret = 0;  if (ql <= M) ret += query(LSON);  else maintain(LSON);  if (qr > M)  ret += query(RSON);  else maintain(RSON);  maintain(SELF);  return ret;  }  void init(){for (int i = 1; i <=n; ++ i)scanf("%lld", &w[i]);//读入一些数据root[0] = 0;tail = 0;build(root[0], 1, n);}void doit(){int now =0;while (m--){scanf("%s", inp);if (inp[0] == 'C')//区间更新,now+1{++now;root[now] = root[now - 1];qver = now;scanf("%d%d%d", &ql, &qr, &qans);//ql,qr区间变化qansinsert(root[now], 1, n);}if (inp[0]=='Q')//询问当前{scanf("%d%d", &ql, &qr);qver = now;printf("%lld\n",query(root[now], 1, n));}if (inp[0]=='H')//询问que时间的L,R区间和{scanf("%d%d%d", &ql, &qr, &qver);printf("%lld\n",query(root[qver], 1, n));}if (inp[0] == 'B')//回到过去{scanf("%d", &now);}}puts("");}int main(){while (~scanf("%d%d", &n, &m)){init();doit();}return 0;}


0 0
原创粉丝点击