poj 3225 线段树注意lazy标记

题意令人很忧伤,理解了题意就好办了。题目中集合中的数不只是整数,将线段扩大两倍用于表示开区间,然后用个懒惰标记就ok了。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int nMax=140005;
const int N=65535*2+2;
int res,vis[nMax];
struct Tree
{
    int l,r,f;
    char lazy;
}t[nMax<<2];
#define mid ((t[p].l+t[p].r)>>1)
#define ls (p<<1)
#define rs ((ls)+1)
void slove(int p)
{
    if(t[p].lazy=='U') t[p].lazy='I';
    else if(t[p].lazy=='I') t[p].lazy='U';
    else if(t[p].lazy=='C') t[p].lazy='E';
    else t[p].lazy='C';
}
void pushdown(int p)
{
    if(t[p].lazy!='E')
    {
        if(t[p].lazy=='U') t[ls].f=t[rs].f=1;
        else if(t[p].lazy=='I') t[ls].f=t[rs].f=0;
        else t[ls].f^=1,t[rs].f^=1;
        if(t[p].lazy=='U' || t[p].lazy=='I')
            t[ls].lazy=t[rs].lazy=t[p].lazy;
        else
        {
           slove(ls); slove(rs);
        }
        t[p].lazy='E';
    }
}
void maketree(int p,int l,int r)
{
    t[p].l=l;t[p].r=r;t[p].lazy='E';t[p].f=0;
    if(t[p].l==t[p].r) return;
    maketree(ls,l,mid);
    maketree(rs,mid+1,r);
}
void modify(int p,int l,int r,char c)
{
    if(l>r) return;
    if(t[p].l==l&&t[p].r==r)
    {
        if(c=='U') t[p].f=1;
        else if(c=='I') t[p].f=0;
        else t[p].f^=1;
        if(c=='U'||c=='I') t[p].lazy=c;
        else slove(p);
        return;
    }
    pushdown(p);
    if(r<=mid) modify(ls,l,r,c);
    else if(l>=mid+1) modify(rs,l,r,c);
    else
    {
        modify(ls,l,mid,c);
        modify(rs,mid+1,r,c);
    }
}
void query(int p)
{
    if(t[p].l==t[p].r)
    {
        if(t[p].f)
        {
            vis[t[p].l]=1;res++;
        }
        return ;
    }
    pushdown(p);
    query(ls); query(rs);
}
int main()
{
//      freopen("test.txt","r",stdin);
      maketree(1,0,N);
      char c,b1,b2;
      int l,r;
      while(scanf("%c %c%d,%d%c",&c,&b1,&l,&r,&b2)!=EOF)
      {
          getchar();
          if(b1=='[') l*=2;
          else l=l*2+1;
          if(b2==']') r*=2;
          else r=r*2-1;
          if(c=='U') modify(1,l,r,'U');
          else if(c=='I')
          {
              modify(1,0,l-1,'I'); modify(1,r+1,N,'I');
          }
          else if(c=='D') modify(1,l,r,'I');
          else if(c=='C')
          {
              modify(1,0,l-1,'I');modify(1,r+1,N,'I');
              modify(1,l,r,'C');
          }
          else modify(1,l,r,'C');
      }
      memset(vis,0,sizeof(vis));res=0;
      query(1);
      int flag=0;
      for(int i=0;i<=N;i++)
      {
          if(vis[i] && !flag)
          {
              flag=1;
              printf("%c%d,",(i%2==0?'[':'('),i/2);
          }
          if(!vis[i] && flag)
          {
              flag=0;
              printf("%d%c ",i/2,(i%2?']':')'));
          }
      }
      if(!res) printf("empty set");
      printf("\n");
      return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值