HDU-1698(线段树set把区间全部更改,懒人标记)

#include
#include
using namespace std;
const int maxn = 1e5 + 5;
long long dat[maxn << 2], setv[maxn << 2];
int v, ql, qr;//该模板从dat[1]开始,父节点存储子节点之和,v存入变化量
void init(int n) {
	fill(dat+1, dat+(n<<2), 1);
	fill(setv+1, setv+(n<<2), -1);//set与add的区别是add是叠加关系,而set是覆盖关系,后一次set会覆盖前一次set,所以set标记必须下推
}                                  
void pushdown(int o) {
	if (setv[o] != -1) {
		setv[o << 1] = setv[o << 1 | 1] = setv[o];
		setv[o] = -1;
	}
}
void maintain(int o, int L, int R) {
                
	if (setv[o]!=-1) dat[o] = setv[o]*(R-L+1);
	else if(L<R)dat[o]=dat[o<<1]+dat[o<<1|1];//父节点的值加上区间长度乘set,就是父节点现在的值
}//L=R的时候说明可能没有子节点了,不用更新
void update(int o, int L, int R) {
	if (ql <= L && R <= qr) setv[o] = v;
	else {
		pushdown(o);//往下推一层,直到完全包含
		int M = (L + R) >> 1;
		if (ql <= M) update(o << 1, L, M); //左子节点等于父节点乘二
		else maintain(o << 1, L, M);
		if(M<qr) update(o << 1 | 1, M + 1, R);//右子节点还要加一
		else maintain(o << 1 | 1, M + 1, R);
	}
	maintain(o, L, R);
}
long long query(int o, int L, int R) {//add是路途上经过的所有add标记之和
	if (ql <= L && R <= qr)
	{
		return dat[o];//完全包含
	}
	if (qr < L || R < ql) return 0;//部分包含
	if (setv[o] != -1) return (long long)setv[o] * (min(R, qr) - max(L, ql) + 1);//遇到set说明这个标记下面的都要被改变,但是不一定都被包含在qr,ql中所以才有了max,min
	long long s = 0;//部分包含且有set
	int M = (L + R) >> 1;
        if (ql <= M)s += query(o << 1, L, M);//继续递归,最后一定会分成上面三种区间并得到结果
	if (M < qr) s += query(o << 1 | 1, M + 1, R);
	return s;
}
int main()
{
	int T;scanf("%d", &T);
	for(int kase=1;kase<=T;kase++){
		int n, q;  scanf("%d%d", &n, &q);
		init(n);
		
		while (q--) {
			    scanf("%d%d%d", &ql, &qr, &v);
				update(1, 1, n);
			}
		ql = 1;qr = n;
		printf("Case %d: The total value of the hook is %lld.\n", kase, query(1, 1, n));
	}
	return 0;
}































你可能感兴趣的:(算法)