线段树

学习

Posted by simplex on April 1, 2021

线段树

以下是一段让人痛苦的代码,其中有挺多的细节,

  • 树的大小要开4倍

  • tk指示的是idx以下的子树的更新,不包括子树自己

    除此之外,还有最最重要的一点,一定要牢记!!!写代码之前一定要想好怎么写!!!

// author: M@
const int maxn=2e5 + 5;
const int maxm = 2e5 + 5;
const int mod = 100003;


int n,m;
int tree[maxn * 4];
char str[maxn];
bool tk[maxn * 4];
int build(int idx, int l, int r){
	if(l == r){
//		printf("tree[%d] = %d\n", idx, tree[idx]);
		return tree[idx] = str[l] - '0';
	}
	int mid = (l + r) / 2;
	tree[idx] = build(idx<<1, l, mid);
	tree[idx] += build(idx<<1|1, mid + 1, r);
//	printf("tree[%d] = %d\n", idx, tree[idx]);
	return tree[idx];
}

void update(int idx, int len){
	if(tk[idx]){
		tk[idx] = false;
		if(len > 1){
			tk[idx<<1] = !tk[idx<<1];
			tk[idx<<1|1] = !tk[idx<<1|1];
//			tree[idx<<1] = (len / 2) - tree[idx<<1];
//			tree[idx<<1|1] = len - (len / 2) - tree[idx<<1|1];
			tree[idx<<1] =  len - (len / 2) - tree[idx<<1];
			tree[idx<<1|1] =(len / 2) - tree[idx<<1|1];
		}
	}
	
}

int push_down(int idx, int l, int r, int tl, int tr){
	int li = idx<<1, ri = idx<<1|1;
	if(l == tl && r == tr){
		tk[idx] = !tk[idx];
		tree[idx] = r - l + 1 - tree[idx];
		update(idx, r - l + 1);
//		printf("%d %d %d  %d  %d tree[idx] %d\n", idx, l, r, tl, tr, tree[idx]);
		return tree[idx];
	}
	int mid = (l + r) / 2;
	update(idx, r - l + 1);
	if(mid >= tl)push_down(li, l, mid, tl, min(tr, mid));
	if(mid < tr)push_down(ri, mid + 1, r, max(tl, mid + 1), tr);
	tree[idx] = tree[li] + tree[ri];
//	printf("%d %d %d  %d  %d tree[idx] %d\n", idx, l, r, tl, tr, tree[idx]);
	return tree[idx];
}

int query(int idx, int l, int r, int tl, int tr){
	int li = idx<<1, ri = idx<<1|1;
	update(idx, r - l + 1);
	if(l == tl && r == tr){
//		printf("%d %d %d  %d  %d tree[idx] %d\n", idx, l, r, tl, tr, tree[idx]);
		return tree[idx];
	}
	int mid = (l + r) / 2;
	int ans = 0;
	if(mid >= tl)ans += query(idx<<1, l, mid, tl, min(tr, mid));
	if(mid < tr)ans += query(idx<<1|1, mid + 1, r, max(tl, mid + 1), tr);	
//	printf("%d %d %d  %d  %d tree[idx] %d\n", idx, l, r, tl, tr, tree[idx]);
	return ans;
}

int main()
{
#ifdef m_
    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
#endif
	scanf("%d%d", &n, &m);
	scanf("%s", str + 1);
	build(1, 1, n);
//	cout<<"sss"<<endl;
	while(m--){
		int op, l, r;
		scanf("%d%d%d", &op, &l, &r);
//		printf("\nop %d %d   %d\n", op, l, r);
		if(op == 0){
			push_down(1, 1, n, l, r);
		}
		else{
			printf("%d\n", query(1, 1, n, l, r));
		}
//		puts("");
	}
	
	
	
#ifdef m_
    fclose(stdin);
//    fclose(stdout);
#endif
    return 0;
}

https://blog.csdn.net/zearot/article/details/48299459