poj3225 区间更新+染色+区间异或+开闭区间划分

题意:给你一些区间的操作,然后利用线段树来模拟,最后求最长区间。

这题比较复杂,主要是怎么处理这些操作。

覆盖的话,只要用col【】数组来搞就行了,有三种状态,-1,0,1,分别表示区间是否被覆盖,全覆盖为0,全覆盖为1。

异或操作的话,在开个Xor【】数组来记录改区间是否被异或过,向下传递异或。

覆盖操作:

把异或标记设置为0,因为覆盖了之后,以前的异或操作就可以不用进行。

异或操作:

如果有覆盖操作,直接把覆盖异或就行了,把异或操作置0

否则,将异或标志与1异或。

向下传递操作:

如果有覆盖标志,那么就子区间覆盖,子区间覆盖标志置1,原区间置0.

如果有异或标志,那么就异或子区间,异或标志向下传递。

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstring>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 131072
#define INF 0xfffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define FOR(i,s,t) for(int i=s;i<=t;i++)
#define ull unsigned long long
#define ll long long
using namespace std;
int col[maxn<<2];
bool Xor[maxn<<2],vis[maxn<<2];
void Fxor(int rt)//1表示覆盖为1,0表示覆盖为0,-1表示没有覆盖
{
    if(col[rt]!=-1)//如果已经被覆盖了,直接把整个区间异或
    {
        col[rt]^=1;
    }
    else//否则记录该区间将要被异或
    {
        Xor[rt]^=1;
    }
}
void PushDown(int rt)
{
    if(col[rt]!=-1)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        Xor[rt<<1]=Xor[rt<<1|1]=0;
        col[rt]=-1;
    }
    if(Xor[rt])
    {
        Fxor(rt<<1);
        Fxor(rt<<1|1);
        Xor[rt]=0;
    }
}
void updata(char op,int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        if(op=='U')
        {
            col[rt]=1;Xor[rt]=0;
        }
        else if(op=='D')
        {
            col[rt]=0;Xor[rt]=0;
        }
        else if(op=='S'||op=='C')
        {
            Fxor(rt);
        }
        return ;
    }
    PushDown(rt);
    int m=(l+r)>>1;
    if(L<=m)
    updata(op,L,R,lson);
    else
    {
        if(op=='I'||op=='C')
        {
            col[rt<<1]=0;Xor[rt<<1]=0;
        }
    }
    if(R>m)
    {
        updata(op,L,R,rson);
    }
    else
    {
        if(op=='I'||op=='C')
        {
            col[rt<<1|1]=0;Xor[rt<<1|1]=0;
        }
    }
}
void query(int l,int r,int rt)
{
    if(col[rt]==1)
    {
        for(int i=l;i<=r;i++)
        {
            vis[i]=1;
        }
        return ;
    }
    else if(col[rt]==0) return ;
    if(l==r) return ;
    PushDown(rt);
    int m=(l+r)>>1;
    query(lson);
    query(rson);
}
int main()
{
    col[1]=Xor[1]=0;
    char op,l,r,m;
    int a,b;
//    freopen("C:\\Users\\lhq\\Desktop\\in.txt","r",stdin);
//    freopen("C:\\Users\\lhq\\Desktop\\out.txt","w",stdout);
    while(scanf("%c %c%d,%d%c\n",&op,&l,&a,&b,&r)!=EOF)
    {
        a<<=1;
        b<<=1;
        if(l=='(') a++;//奇数为开区间端点,偶数为闭区间端点
        if(r==')') b--;
        if(a>b)//a,b区间为空
        {
            if(op=='I'||op=='C')//全区间为覆盖为0
            {
                col[1]=Xor[1]=0;
            }
        }
        else
        {
            updata(op,a,b,0,maxn,1);
        }
    }
    query(0,maxn,1);//查询全区间的状态并标记
    int s=-1,e,flag=0;
    for(int i=0; i<=maxn; i++)
    {
        if(vis[i])
        {
            if(s==-1) s=i;
            e=i;
        }
        else
        {
            if(s!=-1)
            {
                if(flag) printf(" ");
                printf("%c%d%c%d%c",s&1?'(':'[',s>>1,',',(e+1)>>1,e&1?')':']');
                s=-1;
                flag=1;
            }
        }
    }
    if(!flag)
    {
        printf("empty set");
    }
    printf("\n");
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值