[BZOJ3600][线段树][替罪羊树]没有人的算术

%%%vfk
%%%陈老师

本蒟蒻觉得用重量平衡树打tag像是在线的离散……
看到这题的第一感觉也是能不能用很小的复杂度对每一次操作后离散一遍,感觉这确实是个好方法


#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 600010

using namespace std;

struct lef{
  lef *fa,*ch[2],*x,*y;
  int sz;
  double w;
}pr[N],*t,*A[N],*rt,*q[N],*fix;
int tail;

void clear(){
  t=pr;
  A[0]=t++;
  A[0]->w=0;
}

bool operator <(lef a,lef b){
  if(a.x->w==b.x->w) return a.y->w<b.y->w;
  return a.x->w<b.x->w;
}

bool operator ==(lef a,lef b){
  return a.x->w==b.x->w&&a.y->w==b.y->w;
}

inline lef *born(lef* l,lef* r){
  lef *p=t++;
  p->x=l; p->y=r;
  p->fa=p->ch[0]=p->ch[1]=0;
  return p;
}

void dfs(lef *x){
  if(!x) return;
  dfs(x->ch[0]);
  q[++tail]=x;
  dfs(x->ch[1]);
}

inline void updat(lef *x){
  if(!x) return; x->sz=1;
  if(x->ch[0]) x->sz+=x->ch[0]->sz;
  if(x->ch[1]) x->sz+=x->ch[1]->sz;
}

lef *build(int l,int r,double x,double y){
  if(l>r) return 0;
  int mid=l+r>>1;
  double md=(x+y)/2.0;
  q[mid]->w=md;
  q[mid]->ch[0]=build(l,mid-1,x,md);
  q[mid]->ch[1]=build(mid+1,r,md,y);
  updat(q[mid]); return q[mid];
}

lef *rebuild(lef *x,double l,double r){
  tail=0; dfs(x);
  return build(1,tail,l,r);
}

inline int max(lef *a,lef *b){
  int mx=0;
  if(a) mx=max(mx,a->sz);
  if(b) mx=max(mx,b->sz);
  return mx;
}

lef *InserT(lef *&x,lef *y,double l,double r){
  double mid=(l+r)/2.0;
  if(!x){y->w=mid;x=y;return y;}
  if(*x==*y){y->w=mid;return x;}
  lef *p;
  if(x->sz++,*y<*x) p=InserT(x->ch[0],y,l,mid);
  else p=InserT(x->ch[1],y,mid,r);
  if(x->sz*0.75<=max(x->ch[0],x->ch[1])) fix=x;
  else if(fix){
    if(fix==x->ch[0]) x->ch[0]=rebuild(x->ch[0],l,mid);
    else x->ch[1]=rebuild(x->ch[1],mid,r);
    fix=0;
  }
  return p;
}

struct seg{
  int l,r,mx;
}T[N<<2];

inline void updat(int x){
  if(A[T[x<<1].mx]->w>=A[T[x<<1|1].mx]->w) T[x].mx=T[x<<1].mx;
  else T[x].mx=T[x<<1|1].mx;
}

void build(int g,int l,int r){
  T[g].l=l; T[g].r=r; T[g].mx=1;
  if(l==r){T[g].mx=l;return;}
  int mid=l+r>>1;
  build(g<<1,l,mid);
  build(g<<1|1,mid+1,r);
  updat(g);
}

void modify(int g,int x){
  if(T[g].l==T[g].r) {T[g].mx=x;return;}
  int mid=T[g].r+T[g].l>>1;
  if(x<=mid) modify(g<<1,x);
  else modify(g<<1|1,x);
  updat(g);
}

int query(int g,int l,int r){
  if(T[g].l==l&&T[g].r==r) return T[g].mx;
  int mid=T[g].l+T[g].r>>1;
  if(r<=mid) return query(g<<1,l,r);
  if(l>mid) return query(g<<1|1,l,r);
  int lq=query(g<<1,l,mid),rq=query(g<<1|1,mid+1,r);
  if(A[lq]->w<A[rq]->w) return rq; else return lq;
}

int n,m,x,y,z;
char op;

inline char C(){
  static char buf[100000],*p1=buf,*p2=buf;
  if(p1==p2){
    p2=(p1=buf)+fread(buf,1,100000,stdin);
    if(p1==p2) return EOF;
  }
  return *p1++;
}

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

int main(){
  reaD(n); reaD(m);
  clear();
  for(int i=1;i<=n;i++)
    A[i]=InserT(rt,born(A[0],A[0]),0,1);
  build(1,1,n);
  for(int i=1;i<=m;i++){
    while((op=C())!='C'&&op!='Q');
    if(op=='C'){
      reaD(x); reaD(y); reaD(z);
      A[z]=InserT(rt,born(A[x],A[y]),0,1);
      if(fix) rt=rebuild(rt,0,1),fix=0;
      modify(1,z);
    }
    else{
      reaD(x); reaD(y);
      printf("%d\n",query(1,x,y));
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值