`
java-mans
  • 浏览: 11413801 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

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

就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新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|1
using 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 3468A 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|1
using 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|1
using 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: sdj22251
PROG: inflate
LANG: 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 1000000000
using 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|1
using 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;
}


分享到:
评论

相关推荐

    线段树题目

    大量线段树题目 zoj 1610 线段覆盖 poj 2777 线段覆盖 poj 2528 需要离散化,建树不同,需要处理不同-&gt;注意这组数据 3 1 10 1 3 6 10 the ans is 3. hdu 1754 求区间最大值 hdu 1166 求区间和 hdu 1698 成段更新 ...

    java源码包---java 源码 大量 实例

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    JAVA上百实例源码以及开源项目源代码

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    JAVA上百实例源码以及开源项目

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    java源码包2

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    java源码包3

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

    java源码包4

    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...

Global site tag (gtag.js) - Google Analytics