[BZOJ3189][Coci2011][扫描线][线段树]Slika

首先发现LOAD和与其对应的SAVE之间的操作是没用的,所以可以O(m)扫两遍出去SAVE和LOAD操作。

对于这种矩形覆盖的问题,可以用扫面线加线段树处理。
开两棵线段树,用来记录(x+y)为奇数或偶数的时候被覆盖的情况,我们不妨扫描线扫x坐标,那么随着x+1,只要交换一下两颗线段树就可以了。

对于线段树中的一个结点,开一个set记录一下覆盖了这个结点表示的区间的颜色以及时间,以时间为关键字(我直接记录时间,在外面开个数组记录每个时间对应的颜色),这样就相当于区间覆盖,单点查询。

本地跑得贼慢,交到OJ上跑得比被抓的余畅还

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#define N 1010
#define M 100010

using namespace std;

int n,m,k,t;
int S[M],cl[M];
char c[N];
struct stp{
  int op,x1,y1,x2,y2,c,t;
}A[M];
vector<stp> b[N],e[N];
struct seg{
  int l,r;
  set<int,greater<int> > S;
};

struct tree{
  int L,R,Maxx;
  seg T[2][N<<3];
  tree(){ L=0; R=1; }
  void Swap(){ swap(L,R); }
  void insert(int g,int l,int r,int t,int p){
    if(T[p][g].l==l&&T[p][g].r==r) return (void)T[p][g].S.insert(t);
    int mid=T[p][g].l+T[p][g].r>>1;
    if(r<=mid) insert(g<<1,l,r,t,p);
    else if(l>mid) insert(g<<1|1,l,r,t,p);
    else insert(g<<1,l,mid,t,p),insert(g<<1|1,mid+1,r,t,p);
  }
  void erase(int g,int l,int r,int x,int p){
    if(T[p][g].l==l&&T[p][g].r==r) return (void)T[p][g].S.erase(x); 
    int mid=T[p][g].l+T[p][g].r>>1;
    if(r<=mid) erase(g<<1,l,r,x,p);
    else if(l>mid) erase(g<<1|1,l,r,x,p);
    else erase(g<<1,l,mid,x,p),erase(g<<1|1,mid+1,r,x,p);
  }
  void erase(stp x){
    if(((x.x2-x.x1+1)&1)^(x.y1&1))
      erase(1,x.y1,x.y2,x.t,L);
    else
      erase(1,x.y1,x.y2,x.t,R);
  }
  void insert(stp x){
    if(x.y1&1) insert(1,x.y1,x.y2,x.t,L);
    else insert(1,x.y1,x.y2,x.t,R);
  }
  void query(int g,int x,int p){
    if(!T[p][g].S.empty()) Maxx=max(Maxx,*T[p][g].S.begin());
    if(T[p][g].l==T[p][g].r) return ;
    int mid=T[p][g].l+T[p][g].r>>1;
    if(x<=mid) query(g<<1,x,p);
    else query(g<<1|1,x,p);
  }
  int query(int x){
    Maxx=0; query(1,x,(x&1)?L:R);
    return Maxx;
  }
  void Build(int g,int l,int r,int p){
    T[p][g].l=l; T[p][g].r=r; T[p][g].S.clear();
    if(l==r) return ;
    int mid=l+r>>1;
    Build(g<<1,l,mid,p); Build(g<<1|1,mid+1,r,p);
  }
  void build(){
    Build(1,1,n,0); Build(1,1,n,1);
  }
}T;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline void rea(char *x){
  char c=nc(); int len=0;
  for(;c>'Z'||c<'A';c=nc());for(;c>='A'&&c<='Z';x[len++]=c,c=nc());
}

int main(){
  rea(n); rea(k); rea(m); cl[0]=1;
  for(int i=1;i<=m;i++){
    rea(c); A[i].t=i;
    if(c[0]=='S') A[i].op=1;
    else if(c[0]=='L') A[i].op=2,rea(A[i].c);
    else{
      rea(A[i].c),rea(A[i].x1),rea(A[i].y1),rea(A[i].x2),rea(A[i].y2);
      A[i].x1++; A[i].x2++; A[i].y1++; A[i].y2++;
      cl[i]=A[i].c; 
    }
  }
  for(int i=1;i<=m;i++) if(A[i].op==1) S[++t]=i;
  /*for(int i=m;i>0;i--){
    if(A[i].op==0) printf("%d %d\n",A[i].x1,A[i].x2);
    else if(A[i].op==2) i=S[A[i].c];
  }
  return 0;*/
  for(int i=m;i>0;i--){
    if(A[i].op==0){
      b[A[i].x1].push_back(A[i]);
      e[A[i].x2+1].push_back(A[i]);
    }
    else if(A[i].op==2) i=S[A[i].c];
  }
  T.build();
  for(int i=1;i<=n;i++,putchar('\n')){
    T.Swap();
    for(int j=0;j<e[i].size();j++)
      T.erase(e[i][j]);
    for(int j=0;j<b[i].size();j++)
      T.insert(b[i][j]);
    for(int j=1;j<=n;j++)
      printf("%d ",cl[T.query(j)]);
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值