题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3436

  树状数组做法<猛戳>

  Splay tree的经典题目,有删除和移动操作。首先要离散化各个点,而且对于没有区间还要缩点。对于Top操作,先把目标节点删除,然后移到最左端。Query操作,Splay(tar,0),然后直接访问size。对于Rank操作,通过size产找即可。注意,在每次更新后,都要把处理过的节点都要Splay(tar,0)才能保证复杂度为O(log n),因为这样才能方便下次的访问,因为这个TLE了一个下午+一个晚上。。。。Splay()操作太神了。。

 //STATUS:C++_AC_187MS_4196KB
#include <functional>
#include <algorithm>
#include <iostream>
//#include <ext/rope>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
//using namespace __gnu_cxx;
//define
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1.0)
//typedef
typedef __int64 LL;
typedef unsigned __int64 ULL;
//const
const int N=;
const int INF=0x3f3f3f3f;
const int MOD=,STA=;
const LL LNF=1LL<<;
const double EPS=1e-;
const double OO=1e15;
const int dx[]={-,,,};
const int dy[]={,,,-};
const int day[]={,,,,,,,,,,,,};
//Daily Use ...
inline int sign(double x){return (x>EPS)-(x<-EPS);}
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
//End #define Key_value ch[ch[root][1]][0]
int pre[N<<],ch[N<<][]; //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
int sz[N<<],st[N]; //子树规模,内存池
int root,tot,top; //根节点,根节点数量,内存池容量
//题目特定数据
int op[N],cnt[N<<],s[N<<],e[N<<];
int num[N],p[N];
int T,n,m,up;
//debug部分copy from hh
void Treaval(int x) {
if(x) {
Treaval(ch[x][]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d\n",x,ch[x][],ch[x][],pre[x],sz[x]);
Treaval(ch[x][]);
}
}
void debug() {printf("%d\n",root);Treaval(root);}
//以上Debug
//新建一个结点
void NewNode(int &x,int fa,int k,int size)
{
// if(top)x=st[--top];
// else x=++tot;
x=k;
pre[x]=fa;
sz[x]=cnt[x]=size;
ch[x][]=ch[x][]=; //左右孩子为空
} inline void Push_Up(int x)
{
sz[x]=sz[ch[x][]]+sz[ch[x][]]+cnt[x];
}
//旋转,kind为1为右旋,kind为0为左旋
void Rotate(int x,int kind)
{
int y=pre[x],z=pre[y];
//类似SBT,要把其中一个分支先给父节点
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
//如果父节点不是根结点,则要和父节点的父节点连接起来
if(z)ch[z][ch[z][]==y]=x;
pre[x]=z;
ch[x][kind]=y;
pre[y]=x;
Push_Up(y); //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可
}
//Splay调整,将根为r的子树调整为goal
void Splay(int x,int goal)
{
int y,z,kind;
while(pre[x]!=goal){
//父节点即是目标位置,goal为0表示,父节点就是根结点
y=pre[x];
if(pre[y]==goal){
Rotate(x,ch[y][]==x);
}
else {
kind=ch[pre[y]][]==y;
//两个方向不同,则先左旋再右旋
if(ch[y][kind]==x){
Rotate(x,!kind);
Rotate(x,kind);
}
//两个方向相同,相同方向连续两次
else {
Rotate(y,kind);
Rotate(x,kind);
}
}
}
//更新根结点
Push_Up(x);
if(goal==)root=x;
} int Get_Min(int x)
{
while(ch[x][])x=ch[x][];
return x;
}
//建树,中间结点先建立,然后分别对区间两端在左右子树建立
void BuildTree(int &x,int l,int r,int fa)
{
if(l>r)return;
int mid=(l+r)>>;
NewNode(x,fa,mid,e[mid]-s[mid]+);
BuildTree(ch[x][],l,mid-,x);
BuildTree(ch[x][],mid+,r,x);
Push_Up(x);
} void Init()
{
root=tot=top=;
ch[][]=ch[][]=pre[]=sz[]=cnt[]=; int i,t,k;
char ss[];
p[]=,t=;
for(i=;i<=m;i++){
scanf("%s%d",ss,&num[i]);
op[i]=ss[]=='T'?:ss[]=='Q'?:;
if(op[i])p[t++]=num[i];
}
sort(p,p+t);
for(k=,i=;i<t;i++)
if(p[i]!=p[k])p[++k]=p[i];
for(i=,up=;i<=k;i++){
if(p[i]-p[i-]>){
s[++up]=p[i-]+;
e[up]=p[i]-;
}
s[++up]=p[i];
e[up]=p[i];
}
if(e[up]!=n){
++up;
s[up]=e[up-]+;
e[up]=n;
}
BuildTree(root,,up,);
}
//删除编号为x的节点
void Delete(int x)
{
int y=pre[x],s;
if(sz[x]==cnt[x]){
ch[y][ch[y][]==x]=;
s=y;
}
else if(ch[x][]== || ch[x][]==){
s=ch[x][]?ch[x][]:ch[x][];
if(y)ch[y][ch[y][]==x]=s;
pre[s]=y;
}
else {
s=Get_Min(ch[x][]);
Splay(s,x);
if(ch[x][]){
ch[s][]=ch[x][];
pre[ch[x][]]=s;
}
pre[s]=y;
if(y)ch[y][ch[y][]==x]=s;
}
if(y==)root=s;
Splay(s,);
} void Top(int tar)
{
if(sz[root]==cnt[root])return;
Delete(tar);
int x=Get_Min(root);
ch[x][]=tar;
pre[tar]=x;
sz[tar]=cnt[tar];
ch[tar][]=ch[tar][]=;
Splay(tar,);
} int Query(int tar)
{
Splay(tar,);
return sz[ch[root][]]+cnt[tar];
} int Rank(int k)
{
int x=root;
while(){
if(k>sz[ch[x][]] && k<=sz[ch[x][]]+cnt[x]){
k-=sz[ch[x][]];
break;
}
else if(k<=sz[ch[x][]])
x=ch[x][];
else {
k-=sz[ch[x][]]+cnt[x];
x=ch[x][];
}
}
return s[x]+k-;
} int binary(int l,int r,int tar)
{
int mid;
while(l<r){
mid=(l+r)>>;
if(e[mid]<tar)l=mid+;
else if(s[mid]>tar)r=mid;
else return mid;
}
return -;
} int main()
{
// freopen("in.txt","r",stdin);
int i,j,ca=,tar;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
Init();
printf("Case %d:\n",ca++);
for(i=;i<=m;i++){
if(op[i]){
tar=binary(,up+,num[i]);
if(op[i]==)Top(tar);
else printf("%d\n",Query(tar));
}
else printf("%d\n",Rank(num[i]));
}
}
return ;
}

HDU-3436 Queue-jumpers 树状数组 | Splay tree删除,移动的更多相关文章

  1. 洛谷P3960 列队 NOIp2017 线段树/树状数组/splay

    正解:动态开点线段树 解题报告: 传送门! 因为最近学主席树的时候顺便get到了动态开点线段树?刚好想起来很久很久以前就想做结果一直麻油做的这题,,,所以就做下好了QAQ 然后说下,这题有很多种方法, ...

  2. HDU - 1541 Stars 【树状数组】

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1541 题意 求每个等级的星星有多少个 当前这个星星的左下角 有多少个 星星 它的等级就是多少 和它同一 ...

  3. HDU 3333 | Codeforces 703D 树状数组、离散化

    HDU 3333:http://acm.hdu.edu.cn/showproblem.php?pid=3333 这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序.这里我们需要离散化 ...

  4. hdu-5493 Queue(二分+树状数组)

    题目链接: Queue Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  5. hdu 4267 多维树状数组

    题意:有一个序列 "1 a b k c" means adding c to each of Ai which satisfies a <= i <= b and (i ...

  6. HDU 4777 Rabbit Kingdom 树状数组

    分析:找到每一个点的左边离他最近的不互质数,记录下标(L数组),右边一样如此(R数组),预处理 这个过程需要分解质因数O(n*sqrt(n)) 然后离线,按照区间右端点排序 然后扫一遍,对于当前拍好顺 ...

  7. HDU 6348 序列计数 (树状数组 + DP)

    序列计数 Time Limit: 4500/4000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Subm ...

  8. HDU 4325 Flowers(树状数组+离散化)

    http://acm.hdu.edu.cn/showproblem.php?pid=4325 题意:给出n个区间和m个询问,每个询问为一个x,问有多少个区间包含了x. 思路: 因为数据量比较多,所以需 ...

  9. hdu 5775 Bubble Sort 树状数组

    Bubble Sort 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5775 Description P is a permutation of t ...

随机推荐

  1. sql批量删除wordpress所有日志修订revision

    wordpress日志修订是所有速度慢的罪恶之源,每次在后台发布或修改文章的时候,数据库都会产生一个revision版本的记录,几百篇日志会有几千条日志修订的记录,如果更多文章的话,那一个网页打开可能 ...

  2. MySQL性能优化的21个最佳实践

    http://www.searchdatabase.com.cn/showcontent_38045.htm MySQL性能优化的21个最佳实践 1. 为查询缓存优化你的查询 大多数的MySQL服务器 ...

  3. Android SlidingMenu的getSupportActionBar无法找到的解决

    getSupportActionBar()方法不能用 进入Library中的src下找到SlidingFragmentActivity.java,修改 public class SlidingFrag ...

  4. c缺陷与陷阱笔记-第一章 词法陷阱

    1.运算符的贪心性,匹配最长的运算符,例如 n-->0,从-开始,-是运算符,--是运算符,-->就不是,所以是 n -- > 0,--是 a---b,-是,--是,,---不是,所 ...

  5. VS2013与MySql建立连接;您的项目引用了最新实体框架;但是,找不到数据链接所需的与版本兼容的实体框架数据库 EF6使用Mysql的技巧

    因为之前都是看别人的项目,而没有自己从头到尾建立一个项目,所以这次尝试搭建时就出现了问题,主要是ASP.Net MVC项目中VS2013和MySql的连接. 第一个问题: 数据库表已建好,相应的数据库 ...

  6. HeadFirst设计模式之工厂模式

    一. 1."工厂模式"不是种真正的设计模式,而是一种编程术语 2.The Factory Method Pattern defi nes an interface for crea ...

  7. ArcGIS Runtime for Android开发教程V2.0(4)基础篇---MapView

    原文地址: ArcGIS Runtime for Android开发教程V2.0(4)基础篇---MapView - ArcGIS_Mobile的专栏 - 博客频道 - CSDN.NET http:/ ...

  8. POJ2524——Ubiquitous Religions

    Ubiquitous Religions Description There are so many different religions in the world today that it is ...

  9. python学习笔记六--用户自定义类

    一.类: 1. 面向对象. 2. 定义了新的对象类型. 定义了两个属性:name,pay 定义了两个方法:lastName,giveRaise

  10. JSP JSP工作原理 JSP语法 JSP声明 JSP注释 JSP指令 jsp九大隐式/内置对象

    1 什么是JSP   1)为什么说,Servlet是一个动态Web开发技术呢?     Servlet是基于服务端的一种动态交互技术,     HttpServletRequest表示客户端到服务端的 ...