题意:一条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;
}