POJ 1698
Just a Hook
题意:
给出一个区间N,开始区间内的每一点值都是1
然后给出更新命令Q条,更新区间[x , y]的值为z
求出区间N的总价值(长度 * 价值)
-----------------------------------------------------
看到1<=N<=100,000 , 0<=Q<=100,000
显然一般的n^2算法必然会超时,故需要高效算法
之前写过一个线段树(本题为这辈子写的第二个线段树),貌似差不多,故想到线段树
特点:区间大,成段更新,查询区间总和,综合这些特点,线段树满足!
代码参考了某博主的……
贴上供以后复习用
View Code
#include <cstdio> #define N 400000 struct node { int l , r; int num , value; // num:区间长度的总价值 } tree[N]; int z; void make(int s , int t , int rt) // 建树! { tree[rt].l = s; tree[rt].r = t; int mid = (s + t) / 2; tree[rt].num = t - s + 1; tree[rt].value = 1; if (s == t) return; make(s , mid , 2 * rt); make(mid + 1 , t , 2 * rt + 1); } void change(int x , int y , int rt) { if (tree[rt].value == z) return; // 临界条件 if (x == tree[rt].l && tree[rt].r == y) // 找到某一区间,恰好符合 ,则最好 { tree[rt].value = z; tree[rt].num = (tree[rt].r - tree[rt].l + 1) * tree[rt].value; return; } if (tree[rt].value > 0) // 当前根不满足所找区间,则向下层扫描 { tree[rt * 2].value = tree[rt].value; // 左子树 tree[rt * 2].num = (tree[rt * 2].r - tree[rt * 2].l + 1) * tree[rt * 2].value; tree[rt * 2 + 1].value = tree[rt].value; // 右子树 tree[rt * 2 + 1].num = (tree[rt * 2 + 1].r - tree[rt * 2 + 1].l + 1) * tree[rt * 2 + 1].value; tree[rt].value = 0; // 找过了,清零 } int mid = (tree[rt].l + tree[rt].r) / 2; if (x > mid) change(x , y , rt * 2 + 1); else if (y <= mid) change(x , y , rt * 2); else { change(x , mid , rt * 2); change(mid + 1 , y , rt * 2 + 1); } tree[rt].num = tree[rt * 2].num + tree[rt * 2 + 1].num; // 将左右子树的值加到根上 } int main() { int T , n , Q , x , y; int time = 0; scanf("%d" , &T); while (T --) { scanf("%d" , &n); make (1 , n , 1); scanf("%d" , &Q); while (Q --) { scanf("%d%d%d" , &x , &y , &z); change(x , y , 1); } printf("Case %d: The total value of the hook is %d.\n" , ++time , tree[1].num); } return 0; }