zoukankan      html  css  js  c++  java
  • 高级数据结构基础代码

    树状数组代码:
    
    //前缀和
    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
    ", 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
    ", 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
    ", query(l, r)); 
    		}
    }
    

      

    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);
    

      

  • 相关阅读:
    Balance的数学思想构造辅助函数
    1663. Smallest String With A Given Numeric Value (M)
    1680. Concatenation of Consecutive Binary Numbers (M)
    1631. Path With Minimum Effort (M)
    1437. Check If All 1's Are at Least Length K Places Away (E)
    1329. Sort the Matrix Diagonally (M)
    1657. Determine if Two Strings Are Close (M)
    1673. Find the Most Competitive Subsequence (M)
    1641. Count Sorted Vowel Strings (M)
    1679. Max Number of K-Sum Pairs (M)
  • 原文地址:https://www.cnblogs.com/cutemush/p/14230308.html
Copyright © 2011-2022 走看看