题目大意:
现有N(1 ≤ N ≤ 100,000)个数字,初始时都是1,从左到右编号为1 ~ N,现有只有一种操作"X Y Z”,表示将编号区间[X, Y]中的数字都改成Z(Z只能取1、2、3)。
现有多个测例,测例数题中给出,每个测例中都给出N以及Q(0 ≤ Q ≤ 100,000)次操作,要求对于每个测例都输出最终整个序列中数字的总和。
注释代码:
/*
* Problem ID : HDU 1698 Just a Hook
* Author : Lirx.t.Una
* Language : C
* Run Time : 500 ms
* Run Memory : 496 KB
*/
#include <memory.h>
#include <stdio.h>
//勾刺的最大数量
#define MAXN 100000
#define LFT(T) ( (T) << 1 )
#define RHT(T) ( LFT(T) | 1 )
char seg[MAXN * 3];//线段树,只保存每个结点区间的类型
//0 --> 混合类型,花色
//1、2、3 --> 纯类型,纯色
void
update( int tree, int type, int cl, int cr, int lft, int rht ) {
//将线段树结点tree的结点区间[lft, rht]对区间[cl, cr]的类型进行跟新
//cl、cr为changing lft and rht
//将[cl, cr]所在区间类型改为type
int mid;
int tl, tr;//type_lft and type_rht,左子结点的类型以及右子结点的类型
//[lft, rht]显然是包含[cl, cr]的
//因此如果大区间的type和小区间type一样则无需更新
if ( type == seg[tree] ) return ;
if ( lft == cl && cr == rht ) {//命中,直接覆盖type即可
seg[tree] = type;
return ;
}
//未命中
if ( seg[tree] ) {//如果当前结点为纯色则必须将该色传递给子结点!!!
seg[ LFT(tree) ] = seg[tree];
seg[ RHT(tree) ] = seg[tree];
}//如果当前结点本身就是花的,则其子结点以及孙子结点等保留了真正的染色情况
//因此无需将0传递下去
mid = ( lft + rht ) >> 1;
if ( cr <= mid )
update( LFT(tree), type, cl, cr, lft, mid );
else if ( cl > mid )
update( RHT(tree), type, cl, cr, mid + 1, rht );
else {
update( LFT(tree), type, cl, mid, lft, mid );
update( RHT(tree), type, mid + 1, cr, mid + 1, rht );
}
//最后一定要更新当前结点的类型(及颜色)
tl = seg[ LFT(tree) ];
tr = seg[ RHT(tree) ];
//如果两儿子都是纯色且相同,则表示当前结点被一种颜色完全覆盖
//更新当前结点type的则在查询时本来查到当前结点就可以停止,否则
//就必须再继续向下查询才能得到结果而使复杂度大于logN了
if ( tl && tr && tl == tr ) seg[tree] = tl;
else seg[tree] = 0;//如果两边有花色,或者两边是不同的纯色,都代表当前结点区间为花色
}
int
query( int tree, int lft, int rht ) {//查询tree结点区间[lft, rht]上颜色值的总和
int mid;
if ( seg[tree] ) return ( rht - lft + 1 ) * seg[tree];//纯色
//花色
mid = ( lft + rht ) >> 1;
return query( LFT(tree), lft, mid ) + query( RHT(tree), mid + 1, rht );//一直分解到纯色为止
}
int
main() {
int t, iscn;
int n, m;//勾刺数以及操作数
int lft, rht, type;//临时变量
int i;//计数变量
scanf("%d", &t);
iscn = 0;
while ( t-- ) {
memset(seg, 1, sizeof(seg));//初始时都为纯色1
scanf("%d%d", &n, &m);
while ( m-- ) {
scanf("%d%d%d", &lft, &rht, &type);
update( 1, type, lft, rht, 1, n );
}
printf("Case %d: The total value of the hook is %d.\n",
++iscn, query( 1, 1, n ));
}
return 0;
}
无注释代码:
#include <memory.h>
#include <stdio.h>
#define MAXN 100000
#define LFT(T) ( (T) << 1 )
#define RHT(T) ( LFT(T) | 1 )
char seg[MAXN * 3];
void
update( int tree, int type, int cl, int cr, int lft, int rht ) {
int mid;
int tl, tr;
if ( type == seg[tree] ) return ;
if ( lft == cl && cr == rht ) {
seg[tree] = type;
return ;
}
if ( seg[tree] ) {
seg[ LFT(tree) ] = seg[tree];
seg[ RHT(tree) ] = seg[tree];
}
mid = ( lft + rht ) >> 1;
if ( cr <= mid )
update( LFT(tree), type, cl, cr, lft, mid );
else if ( cl > mid )
update( RHT(tree), type, cl, cr, mid + 1, rht );
else {
update( LFT(tree), type, cl, mid, lft, mid );
update( RHT(tree), type, mid + 1, cr, mid + 1, rht );
}
tl = seg[ LFT(tree) ];
tr = seg[ RHT(tree) ];
if ( tl && tr && tl == tr ) seg[tree] = tl;
else seg[tree] = 0;
}
int
query( int tree, int lft, int rht ) {
int mid;
if ( seg[tree] ) return ( rht - lft + 1 ) * seg[tree];
mid = ( lft + rht ) >> 1;
return query( LFT(tree), lft, mid ) + query( RHT(tree), mid + 1, rht );
}
int
main() {
int t, iscn;
int n, m;
int lft, rht, type;
int i;
scanf("%d", &t);
iscn = 0;
while ( t-- ) {
memset(seg, 1, sizeof(seg));
scanf("%d%d", &n, &m);
while ( m-- ) {
scanf("%d%d%d", &lft, &rht, &type);
update( 1, type, lft, rht, 1, n );
}
printf("Case %d: The total value of the hook is %d.\n",
++iscn, query( 1, 1, n ));
}
return 0;
}
单词解释:
cupreous:adj, 铜的,含铜的
metallic:adj, 金属的,含金属的
hook:n, 挂钩,吊钩
pudge:n, 矮胖的人