http://acm.hdu.edu.cn/showproblem.php?pid=1698
题目背景是dotA,题的大致意思是给一组棍子染色,不同的颜色有不同的值,执行一系列的区间染色后,问这组棍子的总值是多少。
采用线段树的做法,但是此题数据很大,如果每一次更新时,对每一个底层的节点都更新的话超时了。故只对需要的节点进行更新,经过参考网上的高手的代码,我知道了其中的一种,就是更新节点后,把更新节点之前的节点标记为不可用,这样,在最后统计的时候,只要统计那些不是不可用的节点的总值就可以了。
#include <stdio.h> #define MAX 100005 typedef struct _node { int left; int right; int count; }node; node no[MAX*3]; int n, value; void insert(int l, int r, int i) { no[i].left = l,no[i].right = r; no[i].count = 1; if(l==r){ return ; } int mid = (l+r)/2; insert(l, mid, 2*i); insert(mid+1, r, 2*i+1); // no[i].count = no[i*2].count + no[2*i+1].count; } void modify(int start, int end, int i) { if(no[i].count == value)return;//相同则不需要再更新 if(no[i].left==start&&no[i].right==end){ no[i].count = value; return; } //将改点标记为不可用点 if(no[i].count!=-1){ no[i*2].count=no[i*2+1].count=no[i].count; no[i].count=-1; } int mid = (no[i].left+no[i].right)/2; if(end <= mid){ modify(start, end, i*2); } else if(start > mid){ modify(start, end, 2*i+1); } else{ modify(start, mid, i*2); modify(mid+1, end, 2*i+1); } } int search(int i)//统计总共有多少 { if(no[i].count!=-1)return (no[i].right-no[i].left+1)*no[i].count; return search(2*i)+search(2*i+1); } int main() { // freopen("input.txt","r",stdin); int cas, t, i; int lf, rg, q; scanf("%d", &cas); for(t = 1; t <= cas; t ++){ scanf("%d", &n); insert(1, n, 1); scanf("%d", &q); for(i = 1; i <= q; i ++){ scanf("%d%d%d", &lf, &rg, &value); modify(lf, rg, 1); } printf("Case %d: The total value of the hook is %d.\n",t, search(1)); } return 0; }