题意:一条DOTA链钩的长度为N,恰恰分成N节,每节价值为1,接着来Q次操作,X Y Z,把[X, Y]节上的价值设为Z,最后输出这条链钩的总价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698
——>>线段树区间修改。
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 100000 + 10; int sumv[maxn<<2], setv[maxn<<2], X, Y, Z, _sum; void maintain(int o, int L, int R) //维护函数 { if(setv[o] >= 0) sumv[o] = setv[o]*(R-L+1); else if(L < R)sumv[o] = sumv[2*o] + sumv[2*o+1]; //L < R } void pushdown(int o) //下传函数 { if(setv[o] >= 0) { setv[2*o] = setv[o]; setv[2*o+1] = setv[o]; setv[o] = -1; } } void update(int o, int L, int R) //更新,将[X, Y]上的值设为Z { if(X <= L && R <= Y) setv[o] = Z; else { pushdown(o); int M = L + (R - L) / 2; if(X <= M) update(2*o, L, M); else maintain(2*o, L, M); if(Y > M) update(2*o+1, M+1, R); else maintain(2*o+1, M+1, R); } maintain(o, L, R); } void query(int o, int L, int R) //查询 { if(setv[o] >= 0) _sum += setv[o] * (min(R, Y)-max(L, X)+1); //递归边界1:有set标记 else if(X <= L && R <= Y) _sum += sumv[o]; //递归边界2:边界区间,此区间不被任何set操作影响 else //递归统计 { int M = L + (R - L) / 2; if(X <= M) query(2*o, L, M); if(Y > M) query(2*o+1, M+1, R); } } void build(int o, int L, int R) //建树 { if(L == R) { sumv[o] = 1; setv[o] = -1; return; } int M = L + (R - L) / 2; build(2*o, L, M); build(2*o+1, M+1, R); sumv[o] = R-L+1; //初始为区间长度 setv[o] = -1; //-1表示没有被标记 } int main() { int T, N, Q, i, cnt = 1; scanf("%d", &T); while(T--) { scanf("%d%d", &N, &Q); build(1, 1, N); for(i = 1; i <= Q; i++) { scanf("%d%d%d", &X, &Y, &Z); update(1, 1, N); } _sum = 0; X = 1; Y = N; //查询[X, Y] query(1, 1, N); printf("Case %d: The total value of the hook is %d.\n", cnt++, _sum); } return 0; }