Fork me on GitHub

POJ 3225 Help with Intervals --线段树区间操作

题意:给你一些区间操作,让你输出最后得出的区间。

解法:区间操作的经典题,借鉴了网上的倍增算法,每次将区间乘以2,然后根据区间开闭情况做微调,这样可以有效处理开闭区间问题。

线段树维护两个值: cov 和 rev  ,一个是覆盖标记,0表示此区间被0覆盖,1表示被1覆盖,-1表示未被覆盖, rev为反转标记,rev = 1表示反转,0表示不翻转

所以集合操作可以化为如下区间操作:

U l r:   把区间[l,r]覆盖成1
I  l r:   把[0,l)(r,MAX]覆盖成0
D l r:   把区间[l,r]覆盖成0
C l r:   把[0,l)(r,MAX]覆盖成0 , 且[l,r]区间0/1互换
S l r:   [l,r]区间0/1互换

重点在于pushdown函数以及边界处理。

代码:

#include <iostream>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
#define N (65536*2)

struct Tree
{
    int cov,rev;   //cov -1  rev 0
}tree[4*N];

struct ANS
{
    char L,R;
    int A,B;
}ans[N+1];
int cnt;

void build(int l,int r,int rt)
{
    tree[rt].cov = 0;
    tree[rt].rev = 0;
    if(l == r) return;
    int mid = (l+r)/2;
    build(l,mid,2*rt);
    build(mid+1,r,2*rt+1);
}

void pushdown(int l,int r,int rt)
{
    if(tree[rt].cov != -1)
    {
        tree[2*rt].cov = tree[2*rt+1].cov = tree[rt].cov;
        tree[2*rt].rev = tree[2*rt+1].rev = 0;
        tree[rt].cov = -1;
    }
    if(tree[rt].rev)
    {
        if(tree[2*rt].cov != -1)
            tree[2*rt].cov ^= 1;
        else
            tree[2*rt].rev ^= 1;

        if(tree[2*rt+1].cov != -1)
            tree[2*rt+1].cov ^= 1;
        else
            tree[2*rt+1].rev ^= 1;
        tree[rt].rev = 0;
    }
}

void update(int l,int r,int aa,int bb,int op,int rt)
{
    if(aa > bb || aa < 0) return;    //必须要加,否则会RE
    if(aa <= l && bb >= r)
    {
        if(op != 2)   //cover to 0/1
        {
            tree[rt].cov = op;
            tree[rt].rev = 0;
        }
        else          //op == 2  reverse
        {
            if(tree[rt].cov != -1)
                tree[rt].cov ^= 1;
            else
                tree[rt].rev ^= 1;
        }
        return;
    }
    pushdown(l,r,rt);
    int mid = (l+r)/2;
    if(aa <= mid)
        update(l,mid,aa,bb,op,2*rt);
    if(bb > mid)
        update(mid+1,r,aa,bb,op,2*rt+1);
}

void query(int l,int r,int rt)
{
    if(tree[rt].cov == 1)
    {
        ans[cnt].L = (l%2==1)?'(':'[';
        ans[cnt].A = l/2;
        ans[cnt].R = (r%2==1)?')':']';
        ans[cnt].B = (r+1)/2;
        cnt++;
    }
    else if(tree[rt].cov == 0) return;
    else
    {
        pushdown(l,r,rt);
        int mid = (l+r)/2;
        query(l,mid,2*rt);
        query(mid+1,r,2*rt+1);
    }
}

void print()
{
    char nowl,nowr;
    int nowA,nowB;
    if(cnt == 0)
        puts("empty set");
    else
    {
        nowl = ans[0].L;
        nowr = ans[0].R;
        nowA = ans[0].A;
        nowB = ans[0].B;
        for(int i=1;i<cnt;i++)
        {
            if(ans[i].A == nowB && (nowr == ']' || ans[i].L == '['))
            {
                nowB = ans[i].B;
                nowr = ans[i].R;
            }
            else
            {
                printf("%c%d,%d%c ",nowl,nowA,nowB,nowr);
                nowl = ans[i].L;
                nowr = ans[i].R;
                nowA = ans[i].A;
                nowB = ans[i].B;
            }
        }
        printf("%c%d,%d%c\n",nowl,nowA,nowB,nowr);
    }
}

int main()
{
    int a,b;
    char L,R,op;
    int n = 65536*2;
    build(0,n,1);
    while(scanf("%c %c%d,%d%c\n",&op,&L,&a,&b,&R)!=EOF) // '\n' 务必要加
    {
        a = 2*a; if(L == '(') a++;
        b = 2*b; if(R == ')') b--;
        if(a > b || a < 0) continue;
        if(op == 'U')  //并集
            update(0,n,a,b,1,1);
        else if(op == 'I')
        {
            update(0,n,0,a-1,0,1);
            update(0,n,b+1,n,0,1);
        }
        else if(op == 'D')
            update(0,n,a,b,0,1);
        else if(op == 'C')
        {
            update(0,n,0,a-1,0,1);
            update(0,n,b+1,n,0,1);
            update(0,n,a,b,2,1);
        }
        else
            update(0,n,a,b,2,1);
    }
    cnt = 0;
    query(0,n,1);
    print();
    return 0;
}
View Code

 

参考文章: http://my.oschina.net/llmm/blog/124256

posted @ 2014-08-28 15:15  whatbeg  阅读(267)  评论(0编辑  收藏  举报