Description

方伯伯正在做他的Oj。现在他在处理Oj上的用户排名问题。
Oj上注册了n个用户,编号为1~”,一开始他们按照编号排名。方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号:
1.操作格式为1 x y,意味着将编号为z的用户编号改为V,而排名不变,执行完该操作后需要输出该用户在队列中的位置,数据保证x必然出现在队列中,同时1,是一个当前不在排名中的编号。
2.操作格式为2 x,意味着将编号为x的用户的排名提升到第一位,执行完该操作后需要输出执行该操作前编号为z用户的排名。
3.操作格式为3 x,意味着将编号为z的用户的排名降到最后一位,执行完该操作后需要输出执行该操作前编号为z用户的排名。
4.操作格式为4 k,意味着查询当前排名为足的用户编号,执行完该操作后需要输出当前操作用户的编号。
但同时为了防止别人监听自己的工作,方伯伯对他的操作进行了加密,即将四种操作的格式分别改为了:
1 x+a y+a
2 x+a
3 x+a
4 k+a
其中a为上一次操作得到的输出,一开始a=0。
例如:
上一次操作得到的输出是5
这一次操作的输入为:1  13 15
因为这个输入是经过加密后的,所以你应该处理的操作是1 8 10
现在你截获丁方伯伯的所有操作,希望你能给出结果。

Input

输入的第1行包含2个用空格分隔的整数n和m,表示初始用户数和操作数。
此后有m行,每行是一个询问,询问格式如上所示。

Output

输出包含m行。每行包含一个整数,其中第i行的整数表示第i个操作的输出。

和 NOIP2017 day2t3 挺像的.
 凭借自己力量独立码出这道题还是超级开心的
 假如说数据范围较小,我们可以对每一个用户开一个点,并用平衡树来维护.
 不过,此题中人数会达到 $10^8$ 级别,这样无论是空间还是时间都承受不了.
 好在操作数 $m$ 最大只有 $10^5$ 级别.
 这意味着其实有许多人之间的相对位置关系是始终不变的(操作数太少)
 我们考虑用动态裂点的方式来维护.
 相比于原来是一个点维护一个人,现在是用一个点维护连续的一排人.
 如果操作的人在一个大的点中,直接分情况讨论将该点裂成 3(或2)个新点即可.
 以上操作可以用 $splay$ 来维护.
 还有一个小小的问题,我们如何知道用户 $x$ 在 $splay$ 中所在点的编号为多少 ?
 由于点和点表示的连续区间是不可能有交集的,我们直接用一个 $set$ 来维护每一个节点的左,右端点与节点编号.
 这样,当我们想知道节点编号时直接在 $set$ 中调用 $lowerbound$ 函数来查即可.
 说起来简单,写起来细节还是挺多的.

普通版:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define maxn 200004
#define lson(x) ch[x][0]
#define rson(x) ch[x][1]
#define get(x) (ch[f[x]][1]==x)
using namespace std;
inline void setIO(string s)
{
string in=s+".in",out=s+".out";
freopen(in.c_str(),"r",stdin);
freopen(out.c_str(),"w",stdout);
}
int n,Q,lastans,root;
int ch[maxn][2], f[maxn], L[maxn], R[maxn], siz[maxn], sta[maxn];
inline int de()
{
int x;
scanf("%d",&x);
return x - lastans;
}
// 右端点从小 -> 大
struct Node
{
int l,r,id;
Node(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
bool operator<(Node b)const { return b.r > r; }
};
set<Node>S;
set<Node>::iterator it;
struct Splay
{
int cnt;
inline void init()
{
cnt=0;
for(int i=1;i<maxn-100;++i) sta[++cnt]=i;
}
inline int newnode()
{
return sta[cnt--];
}
// 内存回收
inline void erase(int x)
{
ch[x][0]=ch[x][1]=f[x]=L[x]=R[x]=siz[x]=0;
sta[++cnt]=x;
}
inline void pushup(int x)
{
siz[x]=siz[lson(x)] + siz[rson(x)] + R[x]-L[x]+1;
}
inline void rotate(int x)
{
int old=f[x],fold=f[old],which=get(x);
ch[old][which]=ch[x][which^1], f[ch[old][which]]=old;
ch[x][which^1]=old, f[old]=x, f[x]=fold;
if(fold) ch[fold][ch[fold][1]==old]=x;
pushup(old), pushup(x);
}
// u -> x
inline void splay(int x,int &u)
{
int a=f[u];
for(int fa;(fa=f[x])!=a;rotate(x))
{
if(f[fa]!=a)
rotate(get(fa)==get(x)?fa:x);
}
u = x;
}
// 查找第 k 大编号
inline int find(int kth)
{
int p = root;
while(1)
{
if(siz[lson(p)] >= kth) p=ch[p][0];
else
{
kth-=(siz[lson(p)]);
if(kth > R[p] - L[p] + 1) kth -= (R[p] - L[p] + 1), p = rson(p);
else
{
return L[p] + kth - 1;
}
}
}
}
inline void del(int x)
{
int p=x;
// root = x
splay(x,root);
if(!ch[x][0] && !ch[x][1]) root = 0;
else if(!ch[x][0]) root = ch[x][1], f[ch[x][1]]=0;
else if(!ch[x][1]) root = ch[x][0], f[ch[x][0]]=0;
else
{
p = ch[x][0];
while(rson(p)) p = rson(p);
splay(p, ch[x][0]);
rson(p) = ch[x][1], f[ch[x][1]] = p, f[p] = 0;
pushup(p);
root=p;
}
S.erase(Node(L[x], R[x],x));
erase(x);
}
// 第 kth 大位置之后进行插入.
inline int insert(int kth,int l,int r)
{
if(!root)
{
root=newnode(), L[root]=l,R[root]=r;
pushup(root);
S.insert(Node(L[root], R[root], root));
return root;
}
int p=root, fa=0, cur=0, tmp=0;
while(p)
{
fa=p;
if(kth >= (tmp=siz[lson(p)] + R[p]-L[p]+1)) kth -= tmp, p=rson(p), cur=1;
else p=lson(p), cur=0;
}
p = newnode();
L[p]=l,R[p]=r;
ch[fa][cur]=p,f[p]=fa;
pushup(p);
splay(p, root);
S.insert(Node(L[p], R[p], p));
return p;
}
// 对于点 x, 割裂出 l
inline int split(int x,int l)
{
splay(x, root);
int tmp = siz[lson(x)],l1=L[x], r1=R[x], oo=0;
// 该点已经单独存在,无需删除
if(l==l1&&l==r1) return x;
if(l==l1)
{
del(x);
oo = insert(tmp,l,l);
insert(tmp+1,l+1,r1);
}
else if(l==r1)
{
del(x);
insert(tmp,l1,r1-1);
oo = insert(tmp+r1-l1,r1,r1);
}
else
{
del(x);
// printf("---------\n");
insert(tmp,l1,l-1); // printf("%d %d\n",l1,l-1);
oo = insert(tmp+l-l1,l,l); // printf("%d %d\n",l,l);
insert(tmp+l-l1+1,l+1,r1); //printf("%d %d\n",l+1,r1);
// for(it=S.begin();it!=S.end();it++) printf("%d %d\n",(*it).l,(*it).r);
}
return oo;
}
}tr;
int main()
{
// setIO("input");
scanf("%d%d",&n,&Q);
tr.init();
tr.insert(0,1,n);
S.insert(Node(1,n,root));
while(Q--)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
// x -> y
int x=de(),y=de(),z;
it=S.lower_bound(Node(0, x, 0));
z = tr.split((*it).id, x);
S.erase(Node(L[z], R[z], z));
S.insert(Node(y,y,z));
tr.splay(z, root), L[z]=R[z]=y, tr.pushup(z), printf("%d\n",lastans=siz[lson(z)]+1);
}
if(opt==2)
{
int x=de(), z, l, r;
it=S.lower_bound(Node(0, x, 0));
z = tr.split((*it).id, x);
tr.splay(z, root), printf("%d\n",lastans=siz[lson(z)]+1);
l = L[z], r=R[z];
tr.del(z), tr.insert(0, l, r);
}
if(opt==3)
{
int x=de(), z, l, r, kk;
// for(it=S.begin();it!=S.end();it++) printf("%d %d::\n",(*it).l,(*it).r);
it = S.lower_bound(Node(0, x, 0));
z = tr.split((*it).id, x);
tr.splay(z, root), printf("%d\n",lastans=siz[lson(z)]+1);
l = L[z], r = R[z];
tr.del(z);
tr.insert(siz[root], l, r);
}
if(opt==4)
{
int k=de();
printf("%d\n",lastans=tr.find(k));
}
}
return 0;
}

  

卡常版

#include<bits/stdc++.h>
#define maxn 200004
#define lson(x) ch[x][0]
#define rson(x) ch[x][1]
#define get(x) (ch[f[x]][1]==x)
#define rg register
#define O2 __attribute__((optimize("-O2")))
using namespace std;
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {int x=0; char c=nc(); while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x;}
O2 inline void setIO(rg string s)
{
string in=s+".in",out=s+".out";
freopen(in.c_str(),"r",stdin);
freopen(out.c_str(),"w",stdout);
}
int n,Q,lastans,root;
int ch[maxn][2], f[maxn], L[maxn], R[maxn], siz[maxn], sta[maxn];
O2 inline int de()
{
rg int x=rd();
return x - lastans;
}
// 右端点从小 -> 大
struct Node
{
int l,r,id;
Node(rg int l=0,rg int r=0,rg int id=0):l(l),r(r),id(id){}
bool operator<(Node b)const { return b.r > r; }
};
set<Node>S;
set<Node>::iterator it;
struct Splay
{
int cnt;
O2 inline void init()
{
cnt=0;
for(rg int i=1;i<maxn-100;++i) sta[++cnt]=i;
}
O2 inline int newnode()
{
return sta[cnt--];
}
// 内存回收
O2 inline void erase(int x)
{
ch[x][0]=ch[x][1]=f[x]=L[x]=R[x]=siz[x]=0;
sta[++cnt]=x;
}
O2 inline void pushup(int x)
{
siz[x]=siz[lson(x)] + siz[rson(x)] + R[x]-L[x]+1;
}
O2 inline void rotate(int x)
{
rg int old=f[x],fold=f[old],which=get(x);
ch[old][which]=ch[x][which^1], f[ch[old][which]]=old;
ch[x][which^1]=old, f[old]=x, f[x]=fold;
if(fold) ch[fold][ch[fold][1]==old]=x;
pushup(old), pushup(x);
}
// u -> x
O2 inline void splay(int x,int &u)
{
rg int a=f[u];
for(rg int fa;(fa=f[x])!=a;rotate(x))
{
if(f[fa]!=a)
rotate(get(fa)==get(x)?fa:x);
}
u = x;
}
// 查找第 k 大编号
O2 inline int find(int kth)
{
rg int p = root;
while(1)
{
if(siz[lson(p)] >= kth) p=ch[p][0];
else
{
kth-=(siz[lson(p)]);
if(kth > R[p] - L[p] + 1) kth -= (R[p] - L[p] + 1), p = rson(p);
else
{
return L[p] + kth - 1;
}
}
}
}
O2 inline void del(int x)
{
rg int p=x;
// root = x
splay(x,root);
if(!ch[x][0] && !ch[x][1]) root = 0;
else if(!ch[x][0]) root = ch[x][1], f[ch[x][1]]=0;
else if(!ch[x][1]) root = ch[x][0], f[ch[x][0]]=0;
else
{
p = ch[x][0];
while(rson(p)) p = rson(p);
splay(p, ch[x][0]);
rson(p) = ch[x][1], f[ch[x][1]] = p, f[p] = 0;
pushup(p);
root=p;
}
S.erase(Node(L[x], R[x],x));
erase(x);
}
// 第 kth 大位置之后进行插入.
O2 inline int insert(rg int kth,rg int l,rg int r)
{
if(!root)
{
root=newnode(), L[root]=l,R[root]=r;
pushup(root);
S.insert(Node(L[root], R[root], root));
return root;
}
rg int p=root, fa=0, cur=0, tmp=0;
while(p)
{
fa=p;
if(kth >= (tmp=siz[lson(p)] + R[p]-L[p]+1)) kth -= tmp, p=rson(p), cur=1;
else p=lson(p), cur=0;
}
p = newnode();
L[p]=l,R[p]=r;
ch[fa][cur]=p,f[p]=fa;
pushup(p);
splay(p, root);
S.insert(Node(L[p], R[p], p));
return p;
}
// 对于点 x, 割裂出 l
O2 inline int split(rg int x,rg int l)
{
splay(x, root);
rg int tmp = siz[lson(x)],l1=L[x], r1=R[x], oo=0;
// 该点已经单独存在,无需删除
if(l==l1&&l==r1) return x;
if(l==l1)
{
del(x);
oo = insert(tmp,l,l);
insert(tmp+1,l+1,r1);
}
else if(l==r1)
{
del(x);
insert(tmp,l1,r1-1);
oo = insert(tmp+r1-l1,r1,r1);
}
else
{
del(x);
// printf("---------\n");
insert(tmp,l1,l-1); // printf("%d %d\n",l1,l-1);
oo = insert(tmp+l-l1,l,l); // printf("%d %d\n",l,l);
insert(tmp+l-l1+1,l+1,r1); //printf("%d %d\n",l+1,r1);
// for(it=S.begin();it!=S.end();it++) printf("%d %d\n",(*it).l,(*it).r);
}
return oo;
}
}tr;
O2 int main()
{
n=rd(),Q=rd();
tr.init();
tr.insert(0,1,n);
S.insert(Node(1,n,root));
while(Q--)
{
rg int opt=rd();
if(opt==1)
{
// x -> y
rg int x=de(),y=de(),z;
it=S.lower_bound(Node(0, x, 0));
z = tr.split((*it).id, x);
S.erase(Node(L[z], R[z], z));
S.insert(Node(y,y,z));
tr.splay(z, root), L[z]=R[z]=y, tr.pushup(z), printf("%d\n",lastans=siz[lson(z)]+1);
}
if(opt==2)
{
rg int x=de(), z, l, r;
it=S.lower_bound(Node(0, x, 0));
z = tr.split((*it).id, x);
tr.splay(z, root), printf("%d\n",lastans=siz[lson(z)]+1);
l = L[z], r=R[z];
tr.del(z), tr.insert(0, l, r);
}
if(opt==3)
{
rg int x=de(), z, l, r, kk;
it = S.lower_bound(Node(0, x, 0));
z = tr.split((*it).id, x);
tr.splay(z, root), printf("%d\n",lastans=siz[lson(z)]+1);
l = L[z], r = R[z];
tr.del(z);
tr.insert(siz[root], l, r);
}
if(opt==4)
{
rg int k=de();
printf("%d\n",lastans=tr.find(k));
}
}
return 0;
}

  

BZOJ 3595: [Scoi2014]方伯伯的Oj Splay + 动态裂点 + 卡常的更多相关文章

  1. BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap

    3595: [Scoi2014]方伯伯的Oj Time Limit: 6 Sec  Memory Limit: 256 MBSubmit: 102  Solved: 54[Submit][Status ...

  2. luogu P3285 [SCOI2014]方伯伯的OJ splay 线段树

    LINK:方伯伯的OJ 一道稍有质量的线段树题目.不写LCT splay这辈子是不会单独写的 真的! 喜闻乐见的是 题目迷惑选手 \(op==1\) 查改用户在序列中的位置 题目压根没说位置啊 只有排 ...

  3. [Scoi2014]方伯伯的OJ(动态开点splay)

    开始没看数据范围差点以为是这题了:https://www.cnblogs.com/hfctf0210/p/10911340.html 然后看到n<=1e8,怎么这么大? 所以这题需要用动态开点线 ...

  4. 洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树

    洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树 题目描述 方伯伯正在做他的 \(Oj\) .现在他在处理 \(Oj\) 上的用户排名问题. \(Oj\) 上注册了 \(n\) 个用户 ...

  5. bzoj 3597: [Scoi2014]方伯伯运椰子 0/1分数规划

    3597: [Scoi2014]方伯伯运椰子 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 144  Solved: 78[Submit][Status ...

  6. bzoj 3594: [Scoi2014]方伯伯的玉米田 dp树状数组优化

    3594: [Scoi2014]方伯伯的玉米田 Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 314  Solved: 132[Submit][Sta ...

  7. bzoj 3594: [Scoi2014]方伯伯的玉米田

    3594: [Scoi2014]方伯伯的玉米田 Time Limit: 60 Sec  Memory Limit: 128 MB Submit: 1399  Solved: 627 [Submit][ ...

  8. bzoj 3597: [Scoi2014]方伯伯运椰子 [01分数规划 消圈定理 spfa负环]

    3597: [Scoi2014]方伯伯运椰子 题意: from mhy12345 给你一个满流网络,对于每一条边,压缩容量1 需要费用ai,扩展容量1 需要bi, 当前容量上限ci,每单位通过该边花费 ...

  9. [SCOI2014]方伯伯的OJ(线段树)

    方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题.Oj上注册了n个用户,编号为1-n“,一开始他们按照编号排名. 方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号: 1.操作格式为 ...

随机推荐

  1. 【POJ 3140】 Contestants Division

    [题目链接] 点击打开链接 [算法] 树形DP ans = min{ | total - 2 * sum[k] | } (sum为以k为根的子树的权值和) [代码] #include <algo ...

  2. Integer和int的区别(转)

    public class TestInteger { public static void main(String[] args) { int i = 128; Integer i2 = 128; I ...

  3. maven配置文件注意事项

    1:安装完成后在C:\Users\Administrator\.m2有一个文件settings.xml需要修改一下配置 2:设置maven从网上下载的jar包.(时间长会很大).我设置它保存我的电脑位 ...

  4. bzoj 5277: [Usaco2018 Open]Out of Sorts【冒泡排序瞎搞】

    首先考虑快排的递归什么时候停下,显然是当前段只剩下一个数了,也就是一个数两边出现分隔符 然后再考虑计算冒泡长度这个操作,因为有分割,所以我们可以把这些放到一起冒泡,这和递归每个区间冒泡是等价的 所以答 ...

  5. Java中关键字continue、break和return的区别

    Java中关键字continue.break和return的区别: continue:跳出本次循环继续下一次循环 break:   跳出循环体,继续执行循环外的函数体 return:   跳出整个函数 ...

  6. java启动参数一

    java启动参数共分为三类: 其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容: 其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足, ...

  7. Qt之程序发布以及打包成exe安装包

    一.简述 Qt项目开发完成之后,需要打包发布程序,而因为用户电脑上没有Qt配置环境,所以需要将release生成的exe文件和所依赖的dll文件复制到一个文件夹中,然后再用 Inno Setup打包工 ...

  8. synchronized(5)修饰语句块之:synchronized(XXX.class)

    synchronized(XXX.class)有两种写法 synchronized(XXX.class)或者synchronized(obj.getClass()) Class也是一个类xxx.cla ...

  9. Android开发学习——Android Studio配置SVN

    一.基本配置 1. 下载这个,然后双击 安装,按下图这样选 然后 傻瓜式安装 2. 进入Android studio设置:Use Command Line Client 选择浏览到第1步你本地安装 T ...

  10. bootstrap框架栅格系统使用

    使用的前端框架  bootstrap框架 Bootstrap是一个响应式的框架 我们在使用的时候主要使用的是它的网格系统, 1.bootstrap布局 布局容器:.container(用于固定宽度并支 ...