线段树几题 --------- 成段更新

来源:互联网 发布:手机电信4g网络被劫持 编辑:程序博客网 时间:2024/06/06 02:31

线段树的成段更新,需要用到延迟标记

就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候

否则就会退化到O(n)的复杂度

1.hdu 1698  Just a Hook

大意是每次把某一段所有数的值改变成某个值,最后求总和。


#include <iostream>#include <vector>#include <list>#include <map>#include <set>#include <deque>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <cctype>#include <string>#include <cstring>#include <cmath>#include <ctime>#define MAXN 100005#define INF 100000000#define eps 1e-11#define L(x) x<<1#define R(x) x<<1|1using namespace std;struct node{    int left, right, mid;    int cover, len, sum;}tree[4 * MAXN];void make_tree(int s, int e, int C){    tree[C].left = s;    tree[C].right = e;    tree[C].mid = (s + e) / 2;    tree[C].len = tree[C].right - tree[C].left + 1;    tree[C].cover = 1;    tree[C].sum = tree[C].cover * tree[C].len;    if(s == e)    return;    make_tree(s, tree[C].mid, L(C));    make_tree(tree[C].mid + 1, e, R(C));}void up(int C){    tree[C].sum = tree[L(C)].sum + tree[R(C)].sum;}void down(int C){    if(tree[C].cover)    {        tree[L(C)].cover = tree[R(C)].cover = tree[C].cover;        tree[L(C)].sum = tree[L(C)].len * tree[L(C)].cover;        tree[R(C)].sum = tree[R(C)].len * tree[R(C)].cover;        tree[C].cover = 0;    }}void update(int s, int e, int k, int C){    if(tree[C].left >= s && tree[C].right <= e)    {        tree[C].cover = k;        tree[C].sum = tree[C].cover * tree[C].len;        return;    }    down(C);    if(tree[C].mid < s) update(s, e, k, R(C));    else if(tree[C].mid >= e) update(s, e, k, L(C));    else    {        update(s, tree[C].mid, k, L(C));        update(tree[C].mid + 1, e, k, R(C));    }    up(C);}int main(){    //freopen("d:/data.in","r",stdin);    //freopen("d:/data.out","w",stdout);    int t, n, i, x, y, z, cas = 0, m;    scanf("%d", &t);    while(t--)    {        scanf("%d", &n);        make_tree(1, n, 1);        scanf("%d", &m);        for(i = 0; i < m; i++)        {            scanf("%d%d%d", &x, &y, &z);            update(x, y, z, 1);        }        printf("Case %d: The total value of the hook is %d.\n", ++cas, tree[1].sum);    }    return 0;}

2. POJ 3468 A Simple Problem with Integers


这题比上面那道的操作稍微复杂了一点,把某个区间的数统一加上某个值。


#include <iostream>#include <vector>#include <list>#include <map>#include <set>#include <deque>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <cctype>#include <string>#include <cstring>#include <cmath>#include <ctime>#define MAXN 100005#define INF 100000000#define eps 1e-11#define L(x) x<<1#define R(x) x<<1|1using namespace std;struct node{    int left, right, mid;    __int64 cover, len;    __int64 sum;}tree[4 * MAXN];__int64 a[100005];void up(int C){    tree[C].sum = tree[L(C)].sum + tree[R(C)].sum;}void down(int C){    if(tree[C].cover)    {        tree[L(C)].cover += tree[C].cover;        tree[R(C)].cover += tree[C].cover;        tree[L(C)].sum += tree[C].cover * tree[L(C)].len;        tree[R(C)].sum += tree[C].cover * tree[R(C)].len;        tree[C].cover = 0;    }}void make_tree(int s, int e, int C){    tree[C].left = s;    tree[C].right = e;    tree[C].mid = (s + e) / 2;    tree[C].cover = 0;    tree[C].sum = 0;    tree[C].len = tree[C].right - tree[C].left + 1;    if(s == e)    {        tree[C].sum = a[s];        return;    }    make_tree(s, tree[C].mid, L(C));    make_tree(tree[C].mid + 1, e, R(C));    up(C);}void update(int s, int e, __int64 k, int C){    if(tree[C].left >= s && tree[C].right <= e)    {        tree[C].cover += k;        tree[C].sum += k * tree[C].len;        return;    }    down(C);    if(tree[C].mid < s) update(s, e, k, R(C));    else if(tree[C].mid >= e) update(s, e, k, L(C));    else    {        update(s, tree[C].mid, k, L(C));        update(tree[C].mid + 1, e, k, R(C));    }    up(C);}__int64 query(int s, int e, int C){    if(tree[C].left >= s && tree[C].right <= e)    return tree[C].sum;    down(C);    __int64 tmp = 0;    if(tree[C].mid < s) tmp += query(s, e, R(C));    else if(tree[C].mid >= e) tmp += query(s, e, L(C));    else    {        tmp += query(s, tree[C].mid, L(C));        tmp += query(tree[C].mid + 1, e, R(C));    }    return tmp;}int main(){    //freopen("d:/data.in","r",stdin);    //freopen("d:/data.out","w",stdout);    int n, m, i, x, y;    __int64 z;    char s[5];    scanf("%d%d", &n, &m);    for(i = 1; i <= n; i++)    scanf("%I64d", &a[i]);    make_tree(1, n, 1);    while(m--)    {        scanf("%s", s);        if(s[0] == 'Q')        {            scanf("%d%d", &x, &y);            printf("%I64d\n",query(x, y, 1));        }        else if(s[0] == 'C')        {            scanf("%d%d%I64d", &x, &y, &z);            update(x, y, z, 1);        }    }    return 0;}

3.poj  2528 Mayor’s posters

大意就是往墙上按区间涂色,看最后能看见的颜色个数

比较麻烦的就是离散化的事情,先把所有的坐标存下来,去重后映射一下,这时就有些问题了,比如原始坐标是1, 3, 6, 10,映射完了是0, 1, 2, 3,3和6本来中间还有几块的,离散完了成相邻的了,所以这里就要处理一下,1,3,6, 10就要处理成1,2,3,4,6,7,10之类的,总之相邻的坐标之差如果大于1了,就在中间添加一个适当的数表示这之间还有块。

然后就建线段树,查询的时候查整个线段树中颜色的个数就行了。

#include <iostream>#include <vector>#include <list>#include <map>#include <set>#include <deque>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <cctype>#include <string>#include <cstring>#include <cmath>#include <ctime>#define MAXN 10005#define INF 100000000#define eps 1e-11#define L(x) x<<1#define R(x) x<<1|1using namespace std;struct node{    int left, right, mid;    int cover;}tree[16 * MAXN];int a[4 * MAXN];int l[MAXN];int r[MAXN];int ans, n;bool used[MAXN];void make_tree(int s, int e, int C){    tree[C].left = s;    tree[C].right = e;    tree[C].cover = -1;    tree[C].mid = (s + e) / 2;    if(s == e) return;    make_tree(s, tree[C].mid, L(C));    make_tree(tree[C].mid + 1, e, R(C));}void down(int C){    if(tree[C].cover != -1)    {        tree[L(C)].cover = tree[R(C)].cover = tree[C].cover;        tree[C].cover = -1;    }}void update(int s, int e, int k, int C){    if(tree[C].left >= s && tree[C].right <= e)    {        tree[C].cover = k;        return;    }    down(C);    if(tree[C].mid < s) update(s, e, k, R(C));    else if(tree[C].mid >= e) update(s, e, k, L(C));    else    {        update(s, tree[C].mid, k, L(C));        update(tree[C].mid + 1, e, k, R(C));    }}void query(int C){    if(tree[C].cover != -1)    {        if(!used[tree[C].cover])        {            ans++;            used[tree[C].cover] = 1;        }        return;    }    if(tree[C].left == tree[C].right)    return;    query(L(C));    query(R(C));}int b_search(int v){    int left = 0, right = n - 1;    while(left <= right)    {        int mid = (left + right) / 2;        if(a[mid] == v) return mid;        else if(a[mid] > v) right = mid - 1;        else left = mid + 1;    }    return 0;}int main(){    //freopen("d:/data.in","r",stdin);    //freopen("d:/data.out","w",stdout);    int t, m, i;    scanf("%d", &t);    while(t--)    {        ans = 0;        memset(used, 0, sizeof(used));        scanf("%d", &m);        int cnt = 0;        for(i = 0; i < m; i++)        {            scanf("%d%d", &l[i], &r[i]);            a[cnt++] = l[i];            a[cnt++] = r[i];        }        sort(a, a + cnt);        n = unique(a, a + cnt) - a;        for(i = n - 1; i > 0; i--)        {            if(a[i] - a[i - 1] != 1) a[n++] = a[i - 1] + 1;        }        sort(a, a + n);        n = unique(a, a + n) - a;        make_tree(0, n - 1, 1);        for(i = 0; i < m; i++)        {            int ll = b_search(l[i]);            //printf("ll %d\n", ll);            int rr = b_search(r[i]);            update(ll, rr, i, 1);            //printf("rr %d\n", rr);        }        query(1);        printf("%d\n", ans);    }    return 0;}

然后更神的是这道题可以用并查集做

从acmol的空间看的http://blog.acmol.com/?p=751

/*ID: sdj22251PROG: inflateLANG: C++*/#include <iostream>#include <vector>#include <list>#include <map>#include <set>#include <deque>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <cctype>#include <string>#include <cstring>#include <cmath>#include <ctime>#define MAXN 9*9*9*9#define INF 1000000000using namespace std;int hash[10000005];int father[40005];int a[10005], b[10005], x[20005];bool v[40005];int find(int x){    if(father[x] == -1) return x;    int t = find(father[x]);    father[x] = t;    return t;}int main(){    int T, n;    scanf("%d", &T);    while(T--)    {        scanf("%d", &n);        for(int i = 0; i < n; i++)        {            scanf("%d%d", &a[i], &b[i]);            x[2 * i] = a[i];            x[2 * i + 1] = b[i];        }        sort(x, x + 2 * n);        int cnt = unique(x, x + 2 * n) - x;        hash[x[0]] = 0;        for(int i = 1; i < cnt; i++)        {            int flag = 0;            if(x[i - 1] + 1 != x[i]) flag = 1;            hash[x[i]] = hash[x[i - 1]] + flag + 1;        }        int ans = 0;        memset(v, 0, sizeof(v));        memset(father, -1, sizeof(father));        for(int i = n - 1; i >= 0; i--)        {            bool flag = false;            int fa = find(hash[a[i]]), fb;            for(int j = hash[b[i]]; j >= hash[a[i]]; j = fb - 1)            {                fb = find(j);                if(!v[fb]) v[fb] = flag = true;                if(fa != fb) father[fb] = fa;            }            if(flag) ans++;        }        printf("%d\n", ans);    }    return 0;}



4.POJ 2777  Count Color  

几乎与2528一摸一样的题,只不过更加裸了


#include <iostream>#include <vector>#include <list>#include <map>#include <set>#include <deque>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <cctype>#include <string>#include <cstring>#include <cmath>#include <ctime>#define MAXN 100005#define INF 100000000#define eps 1e-11#define L(x) x<<1#define R(x) x<<1|1using namespace std;struct node{    int left, right, mid;    int cover;}tree[4 * MAXN];bool used[33];int ans;void make_tree(int s, int e, int C){    tree[C].left = s;    tree[C].right = e;    tree[C].cover = 1;    tree[C].mid = (s + e) / 2;    if(s == e) return;    make_tree(s, tree[C].mid, L(C));    make_tree(tree[C].mid + 1, e, R(C));}void down(int C){    if(tree[C].cover != -1)    {        tree[L(C)].cover = tree[R(C)].cover = tree[C].cover;        tree[C].cover = -1;    }}void update(int s, int e, int k, int C){    if(tree[C].left >= s && tree[C].right <= e)    {        tree[C].cover = k;        return;    }    down(C);    if(tree[C].mid < s) update(s, e, k, R(C));    else if(tree[C].mid >= e) update(s, e, k, L(C));    else    {        update(s, tree[C].mid, k, L(C));        update(tree[C].mid + 1, e, k, R(C));    }}void query(int s, int e, int C){    if(tree[C].cover != -1)    {        if(!used[tree[C].cover])        {            ans++;            used[tree[C].cover] = 1;        }        return;    }    if(tree[C].left == tree[C].right)    return;    if(tree[C].mid < s) query(s, e, R(C));    else if(tree[C].mid >= e) query(s, e, L(C));    else    {        query(s, tree[C].mid, L(C));        query(tree[C].mid + 1, e, R(C));    }}int main(){    //freopen("d:/data.in","r",stdin);    //freopen("d:/data.out","w",stdout);    int n, m, t, x, y, z, i;    char s[5];    scanf("%d%d%d", &n, &m, &t);    make_tree(1, n, 1);    while(t--)    {        scanf("%s", s);        if(s[0] == 'C')        {            scanf("%d%d%d", &x, &y, &z);            if(x > y) swap(x, y);            update(x, y, z, 1);        }        else        {            scanf("%d%d", &x, &y);            ans = 0;            memset(used, 0, sizeof(used));            query(x, y, 1);            printf("%d\n", ans);        }    }    return 0;}


原创粉丝点击