【学习小结】数据结构复习

kd-tree+替罪羊重构

大概复习了一下kd-tree。
主要就是矩形查询的剪枝。
有时候用替罪羊重构,或者每m次操作重构。
然后矩形k大查询可以线段树套kd-tree : orz claris的常数 : 非递归+只插入右边

比赛的时候感觉比较难写的大数据结构可以大胆用kd-tree水。
根据赛场时间和通过率而定吧

claris的板,我改成了bzoj 4066

#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const double A=0.8;
const int N=200010,M=1600010;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int n,ans,cmp_d,op,X1,Y1,X2,Y2,k;
int tmp[N],deep,need[N],cnt,cur;
int root;

//size : 子树大小 , 用于重构
struct node{int d[2],l,r,Max[2],Min[2],size,a,sum;}t[N];

inline bool cmp(int a,int b){return t[a].d[cmp_d]<t[b].d[cmp_d];}
inline void umax(int&a,int b){if(a<b)a=b;}
inline void umin(int&a,int b){if(a>b)a=b;}
inline void up(int x){
  t[x].size=1+t[t[x].l].size+t[t[x].r].size;
  t[x].sum = t[x].a + t[t[x].l].sum + t[t[x].r].sum;
  if(t[x].l){
    umax(t[x].Max[0],t[t[x].l].Max[0]);
    umin(t[x].Min[0],t[t[x].l].Min[0]);
    umax(t[x].Max[1],t[t[x].l].Max[1]);
    umin(t[x].Min[1],t[t[x].l].Min[1]);
  }
  if(t[x].r){
    umax(t[x].Max[0],t[t[x].r].Max[0]);
    umin(t[x].Min[0],t[t[x].r].Min[0]);
    umax(t[x].Max[1],t[t[x].r].Max[1]);
    umin(t[x].Min[1],t[t[x].r].Min[1]);
  }
}
int build(int l,int r,int D){
  int mid=(l+r)>>1;
  cmp_d=D;
  nth_element(need+l+1,need+mid+1,need+r+1,cmp);
  int x=need[mid];
  t[x].Max[0]=t[x].Min[0]=t[x].d[0];
  t[x].Max[1]=t[x].Min[1]=t[x].d[1];
  if(l!=mid)t[x].l=build(l,mid-1,!D);else t[x].l=0;
  if(r!=mid)t[x].r=build(mid+1,r,!D);else t[x].r=0;
  up(x);
  return x;
}
void dfs(int x){if(x)need[++cnt]=x,dfs(t[x].l),dfs(t[x].r);}
inline void ins(int&root,int now){
  if(!root){root=now;return;}
  for(int D=deep=0,x=root;;D^=1){ //非递归的插入,直接边插入边update
    tmp[++deep]=x;
    umax(t[x].Max[0],t[now].Max[0]);
    umax(t[x].Max[1],t[now].Max[1]);
    umin(t[x].Min[0],t[now].Min[0]);
    umin(t[x].Min[1],t[now].Min[1]);
    t[x].size++ , t[x].sum += t[now].a;
    if(t[now].d[D]>=t[x].d[D]){
      if(!t[x].r){t[x].r=now;break;}else x=t[x].r;
    }else{
      if(!t[x].l){t[x].l=now;break;}else x=t[x].l;
    }
  }
  tmp[++deep]=now;
  if(deep<log(t[root].size)/log(1/A))return;
  while((double)t[t[now].l].size<A*t[now].size&&(double)t[t[now].r].size<A*t[now].size)now=tmp[--deep]; //重构
  if(!now)return;
  if(now==root){
    cnt=0,dfs(root);
    root=build(1,cnt,0);
    return;
  }
  int y=tmp[--deep];
  cnt=0,dfs(now);
  int k=build(1,cnt,deep&1);
  if(t[y].l==now)t[y].l=k;else t[y].r=k;
}
void ask(int x){
  if(!x||t[x].Max[0]<X1||t[x].Min[0]>X2||t[x].Max[1]<Y1||t[x].Min[1]>Y2)return;
  if(t[x].Min[0]>=X1&&t[x].Max[0]<=X2&&t[x].Min[1]>=Y1&&t[x].Max[1]<=Y2){ans+=t[x].sum;return;} //ans 是全局变量,也可以改成return ans
  if(t[x].d[0]>=X1&&t[x].d[0]<=X2&&t[x].d[1]>=Y1&&t[x].d[1]<=Y2)ans += t[x].a;
  ask(t[x].l);ask(t[x].r);
}

int lastans;
int main(){
	scanf("%d",&n);
	while ( 1 ){
		int opt,x,y,A;
		read(opt);
		if ( opt == 3 ) break;
		if ( opt == 1 ){
			read(x) , read(y) , read(A);
			x ^= lastans , y ^= lastans, A ^= lastans;
			++cur;
			t[cur].Max[0]=t[cur].Min[0]=t[cur].d[0]=x;
			t[cur].Max[1]=t[cur].Min[1]=t[cur].d[1]=y;
			t[cur].size = 1 , t[cur].sum = t[cur].a = A;
			ins(root,cur);
		}	
		else{
			read(X1) , read(Y1) , read(X2) , read(Y2);
			X1 ^= lastans , Y1 ^= lastans, X2 ^= lastans , Y2 ^= lastans;
			ans = 0 , ask(root);
			lastans = ans;
			
			printf("%d\n",lastans);	
		}
	}	   
}


后缀平衡树(替罪羊树)

用于维护相对排名
直接用long long。
维护每个节点的区间,权值即为区间中点,巧妙的保证了权值符合二叉排序树的左小右大
重构时记得更改

bzoj 3600: 没有人的算术

#include<bits/stdc++.h>
using namespace std;
 
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
 
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
 
const int N = 5e5 + 10;
const int maxn = 100020;
 
 
int n,st,rt,cnt,tot,cur[N+5],Void[N+5],m;
const double alpha=0.75;
const ll inf = (1ll << 62);
 
struct Scapegoat
{
    int Son[2],Exist,Size,Fac,ls,rs;
    ll L,R,Val;
}node[N+5];

inline void Init()
{
    tot=0;
    for(register int i=N-1;i;--i) Void[++tot]=i;
}
inline bool balance(int x)
{
    return (double)node[x].Fac*alpha>(double)max(node[node[x].Son[0]].Fac,node[node[x].Son[1]].Fac);
}
inline void Build(int x)
{
    node[x].Son[0]=node[x].Son[1]=0,node[x].Size=node[x].Fac=1;
}
inline int Insert(int &x,int ls,int rs,ll L,ll R) //L,R是当前的值域区间
{
    if(!x)
    {
        x = Void[tot--];
        node[x].ls = ls , node[x].rs = rs , node[x].Val = (L + R) >> 1 , node[x].L = L , node[x].R = R;
        node[x].Exist = 1;
        Build(x);
        return x;
    }
    if ( node[ls].Val == node[node[x].ls].Val && node[rs].Val == node[node[x].rs].Val ) return x;
    ++node[x].Size , ++node[x].Fac;
    ll mid = (L + R) >> 1;
    if(node[ls].Val < node[node[x].ls].Val || (node[ls].Val == node[node[x].ls].Val && node[rs].Val < node[node[x].rs].Val) ) return Insert(node[x].Son[0],ls,rs,L,mid);
    return Insert(node[x].Son[1],ls,rs,mid,R);
}
inline void PushUp(int x)
{
    node[x].Size=node[node[x].Son[0]].Size+node[node[x].Son[1]].Size+1,node[x].Fac=node[node[x].Son[0]].Fac+node[node[x].Son[1]].Fac+1; 
}
inline void Traversal(int x)
{
    if(!x) return;
    Traversal(node[x].Son[0]);
    if(node[x].Exist) cur[++cnt]=x;
    else Void[++tot]=x;
    Traversal(node[x].Son[1]);
}
inline void SetUp(int l,int r,int &x,ll L,ll R)
{
    int mid=l+r>>1;x=cur[mid]; ll Mid = (L + R) >> 1; //记得更新每个节点的区间
	node[x].L = L , node[x].R = R , node[x].Val = Mid;
    if(l==r)
    {
       
        Build(x);
        return;
    }
    if(l<mid) SetUp(l,mid-1,node[x].Son[0],L,Mid);
    else node[x].Son[0]=0;
    SetUp(mid+1,r,node[x].Son[1],Mid,R),PushUp(x);
}
inline void ReBuild(int &x)
{
    cnt=0,Traversal(x);
    if(cnt) SetUp(1,cnt,x,node[x].L,node[x].R);
    else x=0;
}
inline void check(int x,ll val)
{
    int s=val<=node[x].Val?0:1;
    while(node[x].Son[s])
    {
        if(!balance(node[x].Son[s])) 
        {
            ReBuild(node[x].Son[s]);
            return;
        }
        x=node[x].Son[s],s=val<=node[x].Val?0:1;
    }
}
inline int get_rank(int v)
{
    int x=rt,rk=1;
    while(x)
    {
        if(node[x].Val>=v) x=node[x].Son[0];
        else rk+=node[node[x].Son[0]].Fac+node[x].Exist,x=node[x].Son[1];
    }
    return rk;
}
inline int get_val(int rk)
{
    int x=rt;
    while(x)
    {
        if(node[x].Exist&&node[node[x].Son[0]].Fac+1==rk) return node[x].Val;
        else if(node[node[x].Son[0]].Fac>=rk) x=node[x].Son[0];
        else rk-=node[x].Exist+node[node[x].Son[0]].Fac,x=node[x].Son[1];
    }
}
inline void Delete(int &x,int rk) //后缀平衡树一般不用删除
{
    if(node[x].Exist&&!((node[node[x].Son[0]].Fac+1)^rk)) 
    {
        node[x].Exist=0,--node[x].Fac;
        return;
    }
    --node[x].Fac;
    if(node[node[x].Son[0]].Fac+node[x].Exist>=rk) Delete(node[x].Son[0],rk);
    else Delete(node[x].Son[1],rk-node[x].Exist-node[node[x].Son[0]].Fac);
}
inline void del(int v)
{
    Delete(rt,get_rank(v));
    if((double)node[rt].Size*alpha>(double)node[rt].Fac) ReBuild(rt);
}
 
namespace SGT{
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
    int id[N << 2],a[N];
     
    void build(int x,int l,int r){
        if ( l == r ){ id[x] = l; return; }
        int mid = (l + r) >> 1;
        build(ls(x),l,mid) , build(rs(x),mid + 1,r);
        id[x] = l;
    }
    inline int update(int p1,int p2){
        if ( !p1 ) return p2;
        if ( !p2 ) return p1;
        if ( node[a[p1]].Val > node[a[p2]].Val || (node[a[p1]].Val == node[a[p2]].Val && p1 < p2) ) return p1;
        return p2;      
    }
    void modify(int x,int l,int r,int p,int num){
        if ( l == r ){
            a[l] = num;
            id[x] = l;
            return;
        }
        int mid = (l + r) >> 1;
        if ( p <= mid ) modify(ls(x),l,mid,p,num);
        else modify(rs(x),mid + 1,r,p,num);
        id[x] = update(id[ls(x)],id[rs(x)]);
    }
    int query(int x,int l,int r,int L,int R){
        if ( L <= l && R >= r ){
            return id[x];
        }
        int mid = (l + r) >> 1;
        int res1 = 0 , res2 = 0;
        if ( L <= mid ) res1 = query(ls(x),l,mid,L,R);
        if ( R > mid ) res2 = query(rs(x),mid + 1,r,L,R);
        return update(res1,res2);
    }
}
void init(){
    Init();
    int cur = Insert(rt,0,0,0,inf);
    rep(i,1,n) SGT::a[i] = cur;
    SGT::build(1,1,n);
}
int main()
{
 //   freopen("input.txt","r",stdin);
    scanf("%d %d",&n,&m);
    init();
    while ( m-- ){
        char ch[10]; int l,r,k;
        scanf("%s",ch);
        if ( ch[0] == 'C' ){
            scanf("%d %d %d",&l,&r,&k);
            st = rt;
            int cur = Insert(rt,SGT::a[l],SGT::a[r],0,inf);
            check(rt,node[cur].Val);
            SGT::a[k] = cur;
            SGT::modify(1,1,n,k,cur);
        //  cout<<"check ";
        //  rep(i,1,n) cout<<SGT::a[i]<<" "<<node[SGT::a[i]].Val<<endl;
        //  cout<<endl;
        }
        else{
            scanf("%d %d",&l,&r);
            printf("%d\n",SGT::query(1,1,n,l,r));
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值