Splay练习3——P3960 列队

本文分享了一种使用splay树解决NOIP2018第二天第三题的方法,通过为每行设置独立的splay树来优化处理大量数据查询与更新操作,实现高效的区间修改与查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

蒟蒻的垂死挣扎

noip2018 D2T3 大毒瘤题   emmmmm................

这题最开始的想法是大力开两棵splay,一棵维护除右边一列的所有节点,一棵维护右边一列,然后yy了很久发现可做,开心的要死,然后开始码,越码越不爽,然后去找了yl dalao (%%%),然后发现可以直接每一行开一棵splay,这样会快很多,(带着所有点一起跑真的是不要命),然后大力学一波struct写函数的操作,美滋滋。

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#define RG register
#define N 2000000
#define ls s[x][0]
#define rs s[x][1]
#define ll long long
#define ld long double
using namespace std;

inline int read(){
  RG int x=0,o=1; RG char ch=getchar();
  while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  if(ch=='-') o=-1,ch=getchar();
  while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x*o;
}

ll siz[N],le[N],fa[N],ri[N]; int s[N][2],n,m,q,tot;

struct SplayTree{
    int root;
    ll Add(RG ll x,RG ll y){
        le[++tot]=x,ri[tot]=y,siz[tot]=y-x;
        return tot;
    }
    void Pushup(RG int x){
        siz[x]=siz[ls]+siz[rs]+ri[x]-le[x];
    }
    void Rotate(RG int x){
        RG int y=fa[x],z=fa[y],k=s[y][1]==x,ot=s[x][k^1];
        s[x][k^1]=y,s[y][k]=ot; if(z) s[z][s[z][1]==y]=x;
        fa[x]=z,fa[y]=x; if(ot) fa[ot]=y; Pushup(y),Pushup(x);
    }
    void Splay(RG int x){
        while(fa[x]){
            RG int y=fa[x],z=fa[y];
            if(z) (s[y][1]==x)^(s[z][1]==y)?Rotate(x):Rotate(y);
            Rotate(x);
        } root=x;
    }
    int Split(RG int x,RG ll K){
        K+=le[x]; RG int y=Add(K,ri[x]); ri[x]=K;
        if(!rs) fa[y]=x,rs=y;
        else{ x=rs;
            while(ls) x=ls;
            fa[y]=x,ls=y;
        } Splay(y); return y;
    }
    ll Delkth(RG ll K){
        RG int x=root;
        while(233){
            if(K>siz[ls]+ri[x]-le[x]) K-=siz[ls]+ri[x]-le[x],x=rs;
            else if(K<=siz[ls]) x=ls;
            else{
                K-=siz[ls];
                if(K<ri[x]-le[x]) Split(x,K);
                if(K>1) x=Split(x,K-1);
                break ;
            }
        }  Splay(x),fa[ls]=fa[rs]=0;
        if(!ls) root=rs;
        else{
            RG int y=ls;
            while(s[y][1]) y=s[y][1];
            Splay(y),root=fa[s[y][1]=rs]=y;
            Pushup(y);
        } return le[x];
    }
    void Insert(RG ll K){
        RG int y=Add(K,K+1);
        if(!root) root=y;
        else{
            RG int x=root;
            while(rs) x=rs;
            Splay(x),fa[rs=y]=x,Pushup(x);
        }
    }
}Splay[N];

int main(){
    n=read(),m=read(),q=read();
    for(RG int i=1;i<=n;++i) Splay[i].root=Splay[i].Add(1LL*i*m-m+1,1LL*i*m);
    for(RG int i=1;i<=n;++i) Splay[0].Insert(1LL*i*m);
    while(q--){
        RG int x=read(),y=read();RG ll ans=0;
        Splay[x].Insert(Splay[0].Delkth(x));
        printf("%lld\n",ans=Splay[x].Delkth(y));
        Splay[0].Insert(ans);
    } return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值