[替罪羊树 动态标号 线段树] BZOJ 3600 没有人的算术

好题啊
首先肯定是线段树 那么考虑我们怎么比较两个数的大小
采用CLJ在重量平衡树和后缀平衡树在信息学奥赛中的应用中提到的标号思想
不妨令每个节点表示一个区间 用区间的中值代表这个数的大小
具体实现是我们不仅要给每个点记录 l,r,mid
还要记录 x y 表示他等价于(x,y)的组合 因为新插入数是没有标号的 只能按定义比较first和second
注意0小于任何数 我没想到好的方法 只能暴力点特殊建一个节点了

替罪羊写的好长 嘤嘤嘤

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
  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 c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(char &x){
  for (x=nc();!(x>='A' && x<='Z');x=nc()); 
}

const int N=600005;
const double oo=1e20;

#define ab 0.75
struct node{
  node *ch[2]; int size;
  double l,r,mid; pair<node*,node*> val;
  bool operator < (const node B){ return mid<B.mid; }
  bool operator == (const node B){ return mid==B.mid; }
  void update() { size=ch[0]->size+ch[1]->size+1; }
  bool bad() { return ch[0]->size>=size*ab+5 || ch[1]->size>=size*ab+5; }
}Mem[N],*root,*null,*zero;
int pnt;

typedef pair<node*,node*> abcd;
bool operator == (abcd A,abcd B){ return *A.first==*B.first && *A.second==*B.second; }
bool operator < (abcd A,abcd B){ return *A.first==*B.first?*A.second<*B.second:*A.first<*B.first; }

inline node *New(abcd key,double l,double r){
  node *t=Mem+(++pnt);
  t->ch[0]=t->ch[1]=null; t->l=l; t->r=r; t->mid=(l+r)/2; t->val=key; t->size=1;
  return t;
}
inline void Init(){
  root=null=Mem; null->ch[0]=null->ch[1]=null;
  zero=Mem+(++pnt); zero->mid=-1e30;
}
node *lst[N]; int len;
inline void travel(node *p){
  if (p==null) return;
  travel(p->ch[0]); lst[++len]=p; travel(p->ch[1]);
}
inline node* divide(double l,double r,int lp,int rp){
  if (lp>rp) return null;
  int mid=(lp+rp)>>1; double m=(l+r)/2;
  lst[mid]->ch[0]=divide(l,m,lp,mid-1); lst[mid]->ch[1]=divide(m,r,mid+1,rp); lst[mid]->update();
  lst[mid]->l=l; lst[mid]->r=r; lst[mid]->mid=m;
  return lst[mid];
}
inline void rebuild(node *&p){
  len=0; travel(p); p=divide(p->l,p->r,1,len);
}
inline node **insert(node *&p,double l,double r,abcd key){
  if (p==null){ p=New(key,l,r); return &null; }
  p->size++;
  node **ret;
  if (p->val<key)
    ret=insert(p->ch[1],p->mid,p->r,key);
  else
    ret=insert(p->ch[0],p->l,p->mid,key);
  if (p->bad()) ret=&p;
  return ret;
}
inline void Insert(abcd key){
  if (root==null) return void(root=New(key,-oo,oo));
  node **p=insert(root,root->l,root->r,key);
  if (*p!=null) rebuild(*p);
}
inline node *Find(abcd key){
  node *p=root;
  while (p!=null){
    if (key==p->val) break;
    if (key<p->val) p=p->ch[0];
    else p=p->ch[1];
  }
  return p;
}

node *pos[N];
int T[N<<2];

inline int Max(int a,int b){
  if (!a||!b) return a+b;
  if (*pos[a]==*pos[b]) return min(a,b);
  return *pos[a]<*pos[b]?b:a;
}

inline void Build(int x,int l,int r){
  if (l==r) return void(T[x]=l); int mid=(l+r)>>1;
  Build(x<<1,l,mid); Build(x<<1|1,mid+1,r);
  T[x]=Max(T[x<<1],T[x<<1|1]);
}

inline void Modify(int x,int l,int r,int t){
  if (l==r) return; int mid=(l+r)>>1;
  if (t<=mid) Modify(x<<1,l,mid,t);
  else Modify(x<<1|1,mid+1,r,t);
  T[x]=Max(T[x<<1],T[x<<1|1]);
}

int ans;

inline void Query(int x,int l,int r,int ql,int qr){
  if (ql<=l && r<=qr) return void(ans=Max(ans,T[x]));
  int mid=(l+r)>>1;
  if (ql<=mid) Query(x<<1,l,mid,ql,qr);
  if (qr>mid) Query(x<<1|1,mid+1,r,ql,qr);
}

int n;

int main(){
  int Q,l,r,k; char order;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  Init();
  read(n); read(Q);
  for (int i=1;i<=n;i++) pos[i]=zero;
  Build(1,1,n);
  while (Q--){
    read(order); read(l); read(r);
    if (order=='Q'){
      ans=0,Query(1,1,n,l,r),printf("%d\n",ans);
    }else if (order=='C'){
      read(k);
      abcd t=abcd(pos[l],pos[r]);
      node *p=Find(t);
      if (p==null){
    Insert(t),pos[k]=Mem+pnt;
      }else
    pos[k]=p;
      Modify(1,1,n,k);
    }
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值