这题我知道我做过. 但是现在做还是搞了半天.
因为还是对 pushdown 这个没搞清楚. 这个函数不是维护e的 , 而是维护e的 子节点的.
由于这题只要查询一次整段的值, 返回a[1]即可.
代码1 (标准写法, pushdown维护到子节点):
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<string> #include<vector> #include<map> #include<algorithm> using namespace std; inline int Rint() { int x; scanf("%d", &x); return x; } inline int max(int x, int y) { return (x>y)? x: y; } inline int min(int x, int y) { return (x<y)? x: y; } #define FOR(i, a, b) for(int i=(a); i<=(b); i++) #define FORD(i,a,b) for(int i=(a);i>=(b);i--) #define REP(x) for(int i=0; i<(x); i++) typedef long long int64; #define INF (1<<30) const double eps = 1e-8; #define bug(s) cout<<#s<<"="<<s<<" " // 区间更新, 维护区间和, 区间更新要用到 lazy 标记 // 重点是始终维护区间和正确, [add标记只作用于子节点.]!!! #define MAXN 100002 int a[MAXN<<2]; //区间和 int add[MAXN<<2]; //lazy标记 void pushup(int e) // 把子节点信息更新到当前结点 { a[e] = a[e<<1]+a[e<<1|1]; } void pushdown(int l, int r, int e) // 把当前点信息(lazy标记)更新给子节点, 并更新子节点的值 { // pushdown的意义不是维护到e结点, 而是维护到e的子节点!! if(add[e]) { int mid = (l+r)>>1; a[e<<1] = (mid-l+1)*add[e]; //pushdown接受的 e 不可能是叶子 a[e<<1|1] = (r-mid-1+1)*add[e]; add[e<<1] = add[e<<1|1] = add[e]; add[e] = 0; } } void build(int l, int r, int e) { add[e] = 0; if(l==r) a[e]=1; else { int mid = (l+r)>>1; build(l, mid, e<<1); build(mid+1, r, e<<1|1); pushup(e); } } void update(int L, int R, int v, int l, int r, int e) { if(L<=l && r<=R) { a[e]=(r-l+1)*v; //使e结点得到完全维护 add[e] = v; } else { pushdown(l, r, e); int mid = (l+r)>>1; if(L<=mid) update(L, R, v, l, mid, e<<1); if(mid+1<=R) update(L, R , v, mid+1, r, e<<1|1); pushup(e); } } int query(int L, int R, int l, int r, int e) { if(L<=l && r<=R) { return a[e]; } else { pushdown(l, r, e); int mid = (l+r)>>1; int ret = 0; if(L<=mid) ret+=query(L, R, l, mid, e<<1); if(mid+1<=R) ret+=query(L, R, mid+1, r, e<<1|1); //pushup(e); //不需要pushup, 因为pushup的意义是维护结点的主域, 而query并不会新增任何改变(除了扩展lazy标记) return ret; } } int main() { int T =Rint(); FOR(tt, 1, T) { int n = Rint(); int q = Rint(); build(1, n, 1); REP(q) { int x = Rint(); int y = Rint(); int z = Rint(); update(x, y, z, 1, n, 1); } //printf("Case %d: The total value of the hook is %d.\n", tt, query(1, n, 1, n, 1)); printf("Case %d: The total value of the hook is %d.\n", tt, a[1]); } }
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<string> #include<vector> #include<map> #include<algorithm> using namespace std; inline int Rint() { int x; scanf("%d", &x); return x; } inline int max(int x, int y) { return (x>y)? x: y; } inline int min(int x, int y) { return (x<y)? x: y; } #define FOR(i, a, b) for(int i=(a); i<=(b); i++) #define FORD(i,a,b) for(int i=(a);i>=(b);i--) #define REP(x) for(int i=0; i<(x); i++) typedef long long int64; #define INF (1<<30) const double eps = 1e-8; #define bug(s) cout<<#s<<"="<<s<<" " // 区间更新, 维护区间和, 区间更新要用到 lazy 标记 #define MAXN 100002 int a[MAXN<<2]; //区间和 int add[MAXN<<2]; //lazy标记 void pushup(int e) // 把子节点信息更新到当前结点 { a[e] = a[e<<1]+a[e<<1|1]; } void pushdown(int l, int r, int e) // 把当前点信息更新给子节点 { if(add[e]) { a[e]=add[e]*(r-l+1); //不要搞错了, 这个标记真正的意义是把值变成 add*(r-l+1) if(l!=r) add[e<<1] = add[e<<1|1] = add[e]; add[e] = 0; } } void build(int l, int r, int e) { add[e] = 0; if(l==r) a[e]=1; else { int mid = (l+r)>>1; build(l, mid, e<<1); build(mid+1, r, e<<1|1); pushup(e); } } void update(int L, int R, int v, int l, int r, int e) { if(L<=l && r<=R) { add[e] = v; pushdown(l, r, e); } else { int mid = (l+r)>>1; pushdown(l, r, e); pushdown(l, mid, e<<1); //推得不够下. pushdown(mid+1, r, e<<1|1); if(L<=mid) update(L, R, v, l, mid, e<<1); if(mid+1<=R) update(L, R , v, mid+1, r, e<<1|1); pushup(e); } } int main() { int T =Rint(); FOR(tt, 1, T) { int n = Rint(); int q = Rint(); build(1, n, 1); REP(q) { int x = Rint(); int y = Rint(); int z = Rint(); update(x, y, z, 1, n, 1); } printf("Case %d: The total value of the hook is %d.\n", tt, a[1]); } }