高级数据结构基础代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | 树状数组代码: //前缀和 int query( int x){ int ans = 0; for (; x; x -= x& -x) ans += C[x]; return ans; } //单点修改 void modify( int x, int y){ for (; x <= N; x += x & -x) c[x] += y; } //树状数组区改区查 const int SIZE = 100010; int a[SIZE], n, m; long long C[2][SIZE], sum[SIZE]; long long query( int k, int x){ long long ans = 0; for (; x; x -= x & -x) ans += C[k][x]; return ans; } void modify( int k, int x, int y){ for (; x <= n; x += x & -x) C[k][x] += y; } int main(){ cin >> n >> m; for ( int i = 1; i <= n; i++){ scanf ( "%d" , &a[i]); sum[i] = sum[i-1] + a[i]; } while (m--){ char op[2]; int l,r,d; scanf ( "%s%d%d" , op, &l, &r); if (op[0] == 'C' ){ scanf ( "%d" , &d); modify(0, l, d); modify(0, r+1, -d); //0代表C0 modify(1, l, l*d); modify(1, r+1, -(r+1)*d); //1代表C1 } else { //query long long ans = sum[r] + (r+1)*query(0, r) - query(1,r); ans -= sum[l-1] + l * query(0, l-1) - query(1, l-1); printf ( "%lld\n" , ans); } } } //线段树的建立 struct SegmentTree{ int l, r; int dat; } t[SIZE * 4]; void build( int p, int l, int r){ t[p].l = l, t[p].r = r; //节点p代表区间[l,r] if (l == r){ //叶节点 t[p].dat = a[l]; return ; } int mid = (l+r)/2; //折半 build(p*2, l, mid); //左子节点 build(p*2+1, mid+1, r) //右子节点 t[p].dat = max(t[p*2].dat, t[p*2+1].dat); //由下往上维护RMQ性质 } build(1,1,n); //A={3,6,4,8,1,2,9,5,7,0} //线段树的单点修改 void modify( int p, int x, int v){ if (t[p].l == t[p].r) { //叶节点 t[p].dat = v; return ; } int mid = (t[p].l + t[p].r)/2; if (x <= mid) modify(p*2, x ,v) //x属于左子树区间 else modify(p*2+1, x, v) //x属于右子树区间 t[p].dat = max(t[p*2].dat, t[p*2+1].dat); //由下往上维护RMQ性质 } modify(1,x,v); //modify(1,7,1) //线段树的区间查询 int query( int p, int l, int r){ if (l <= t[p].l && r >= t[p].r) return t[p].dat; //完全覆盖 int mid = (t[p].l + t[p].r)/2; int val = -(1<<30); //负极大数 if (l <= mid) val = max(val, query(p*2, l, r)); //左子节点有覆盖 if (r > mid) val = max(val, query(p*2+1, l, r)); //右子节点有覆盖 return val; } cout << query(1,l,r) << endl; //调用入口 //带Lazy Tag的线段树 struct SegmentTree{ int l, r; long long sum, tag; #define l(x) tree[x].l #define r(x) tree[x].r #define sum(x) tree[x].sum #define tag(x) tree[x].tag } t[SIZE * 4]; int a[SIZE], n, m; void build( int p, int l, int r){ l(p) = l, r(p) = r; //节点p代表区间[l,r] if (l == r){ //叶节点 sum(p) = a[l]; return ; } int mid = (l+r)/2; //折半 build(p*2, l, mid); //左子节点 build(p*2+1, mid+1, r) //右子节点 sum(p) = sum(p*2) + sum(p*2+1); } void spread( int p){ if (tag(p)) { //节点p有标记 sum(p*2) += tag(p)*(r(p*2) - l(p*2)+1); //更新左子节点 sum(p*2+1) += tag(p)*(r(p*2+1) - l(p*2+1)+1); //更新右子节点 tag(p*2) += tag(p); //在左子节点更新标记 tag(p*2+1) += tag(p); //在右子节点更新标记 tag(p) = 0; //本节点标记清除 } } //区间修改 void modify( int p, int l, int r, int v){ if (l <= l(p) && r >= r(p)) { //完全覆盖 sum(p) += ( long long )v * (r(p)-l(p)+1); //更新节点信息 tag(p) += v; // 更新节点的标记信息 return ; } spread(p); //如果区间未完全被覆盖,则往下传递标记信息 int mid = (l(p) + r(p))/2; if (l <= mid) modify(p*2, l, r, v) //修改左子树区间 if (r > mid) modify(p*2+1, l, r, v) //修改右子树区间 sum(p) = sum(p*2) + sum(p*2+1); } //区间查询 int query( int p, int l, int r){ if (l <= l(p) && r >= r(p)) return sum(p); //完全覆盖 spread(p); //如果区间未完全被覆盖,查询的时候也顺便传递标记信息 int mid = (l(p) + r(p))/2; long long val = 0; if (l <= mid) val += query(p*2, l, r) //查询左子树区间,更新答案 if (r > mid) val += query(p*2+1, l, r) //修改右子树区间,更新答案 return val; } int main(){ cin >> n >> m; for ( int i = 1; i <= n; i++) scanf ( "%d" , &a[i]); build(1, 1, n); while (m--){ char op[2]; int l,r,v; scanf ( "%s%d%d" , op, &l, &r); if (op[0] == 'C' ){ scanf ( "%d" , &v); modify(1, l, r, v); } else printf ( "%lld\n" , query(1, l, r)); } } //分块算法 long long a[SIZE], sum[SIZE], tag[SIZE]; int L[SIZE], R[SIZE]; //每段左右端点 int pos[SIZE]; //每个位置属于哪一段 int n, m, t; //区间修改 void modify( int l, int r, long long v){ int p = pos[l], q = pos[r]; //查询区间所在的段编号 if (p == q){ //同段内朴素求和 for ( int i = l; i <= r; i++) a[i] += v; sum[p] += v*(r - l + 1); } else { for ( int i = p+1; i <= q-1; i++) tag[i] += v; //更新段的标记信息 for ( int i = l; i <= R[p]; i++) a[i] += v; //最左不足一段的区间 sum[p] += v*(R[p] - l + 1); //更新段的前缀和 for ( int i = L[q]; i <= r; i++) a[i] += v; //最右不足一段的区间 sum[q] += v*(r - L[p] + 1); //更新段的前缀和 } } //区间查询 void query( int l, int r){ int p = pos[l], q = pos[r]; long long ans = 0; if (p == q){ for ( int i = l; i <= r; i++) ans += a[i]; ans += tag[p] * (r - l + 1); //莫忘此段的标记信息 } else { for ( int i = p+1; i <= q-1; i++) //完整多段的求和 ans += sum[i] + tag[i] * (R[i]-L[i]+1); for ( int i = l; i <= R[p]; i++) ans += a[i]; //最左不足一段的区间 ans += tag[p] * (R[p] - l + 1); for ( int i = L[q]; i <= r; i++) ans += a[i]; //最右不足一段的区间 ans += tag[p] * (r - L[p] + 1); } return ans; } int main(){ cin >> n >> m; for ( int i = 1; i <= n; i++) scanf ( "%lld" , &a[i]); //分块 t = sqrt (n*1.0); for ( int i = 1; i <= t; i++){ //各段的左右端点 L[i] = (i-1) * sqrt (n) + 1; R[i] = i * sqrt (n); } if (R[t] < n){ //最末尾的一段 t++; L[t] = R[t-1] + 1; R[t] = n; } //预处理 各个点属于哪一段,以及每段的前缀和 for ( int i = 1; i <= t; i++){ for ( int j = L[i]; j <= R[i]; j++){ pos[j] = i; sum[i] += a[j]; } } //指令 while (m--){ char op[3]; int l,r,v; scanf ( "%s%d%d" , op, &l, &r); if (op[0] == 'C' ){ scanf ( "%d" , &v); modify(l, r, v); } else printf ( "%lld\n" , query(l, r)); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | struct SegmentTree { int lc, rc; // 左右子节点编号 int dat; // 区间最大值 } tree[MAX_MLOGN]; int tot, root[MAX_M]; // 可持久化线段树的总点数和每个根 int n, a; int build( int l, int r) { int p = ++tot; if (l == r) { tree[p].dat = a[l]; return p; } int mid = (l + r) >> 1; tree[p].lc = build(l, mid); tree[p].rc = build(mid + 1, r); tree[p].dat = max(tree[tree[p].lc].dat, tree[tree[p].rc].dat); return p; } // 在main函数中 root[0] = build(1, n); //对于第i次修改,以可持久化线段树的第i-1个版本为基础,下面实现单点修改操作 int insert( int now, int l, int r, int x, int val) { int p = ++tot; //总点数+1 tree[p] = tree[now]; //now为当前节点 if (l == r) { tree[p].dat = val; return p; } int mid = (l + r) >> 1; if (x <= mid) tree[p].lc = insert(tree[now].lc, l, mid, x, val); //在这里实现logN个新节点的创建 else tree[p].rc = insert(tree[now].lc, mid + 1, r, x, val); //同上 tree[p].dat = max(tree[tree[p].lc].dat, tree[tree[p].rc].dat); //维护区间性质 return p; } // 在main函数中 root[i] = insert(root[i - 1], 1, n, x, val); |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步