HDU-3436 Queue-jumpers 树状数组 | Splay tree删除,移动
题目链接: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删除,移动的更多相关文章
- 洛谷P3960 列队 NOIp2017 线段树/树状数组/splay
正解:动态开点线段树 解题报告: 传送门! 因为最近学主席树的时候顺便get到了动态开点线段树?刚好想起来很久很久以前就想做结果一直麻油做的这题,,,所以就做下好了QAQ 然后说下,这题有很多种方法, ...
- HDU - 1541 Stars 【树状数组】
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1541 题意 求每个等级的星星有多少个 当前这个星星的左下角 有多少个 星星 它的等级就是多少 和它同一 ...
- HDU 3333 | Codeforces 703D 树状数组、离散化
HDU 3333:http://acm.hdu.edu.cn/showproblem.php?pid=3333 这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序.这里我们需要离散化 ...
- hdu-5493 Queue(二分+树状数组)
题目链接: Queue Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total ...
- hdu 4267 多维树状数组
题意:有一个序列 "1 a b k c" means adding c to each of Ai which satisfies a <= i <= b and (i ...
- HDU 4777 Rabbit Kingdom 树状数组
分析:找到每一个点的左边离他最近的不互质数,记录下标(L数组),右边一样如此(R数组),预处理 这个过程需要分解质因数O(n*sqrt(n)) 然后离线,按照区间右端点排序 然后扫一遍,对于当前拍好顺 ...
- HDU 6348 序列计数 (树状数组 + DP)
序列计数 Time Limit: 4500/4000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Subm ...
- HDU 4325 Flowers(树状数组+离散化)
http://acm.hdu.edu.cn/showproblem.php?pid=4325 题意:给出n个区间和m个询问,每个询问为一个x,问有多少个区间包含了x. 思路: 因为数据量比较多,所以需 ...
- hdu 5775 Bubble Sort 树状数组
Bubble Sort 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5775 Description P is a permutation of t ...
随机推荐
- JAVA与ABA问题
在<JAVA并发编程实战>的第15.4.4节中看到了一些关于ABA问题的描述.有一篇文章摘录了书里的内容. 书中有一段内容为: 如果在算法中采用自己的方式来管理节点对象的内存,那么可能出现 ...
- firefly 框架 结构图
原地址:http://www.9miao.com/question-15-54838.html 系统结构:
- 从零开始运维之旅:如何监控你的 Windows?
小弟乃刚刚踏入运维圈的资深小白一枚,正所谓完事开头难,公司里怕我把生产系统搞坏就让我先在测试环境上先练练手.巧的是测试环境又是我熟悉的 Windows 环境,心中窃喜啊.但问题随之而来,运维从何下手呢 ...
- express 3.0.x 中默认不支持flash() 的解决方法
Express 3.x默认已经不支持req.flash(),如果要用flash()需要这样兼容 1.flash 消息暂存在session中,需要cookieParser 和 session中间件来声明 ...
- http://www.cnblogs.com/amboyna/archive/2008/03/08/1096024.html
http://www.cnblogs.com/amboyna/archive/2008/03/08/1096024.html
- POJ 3904 Sky Code
题意:给定n个数ai, ai <= 10000, n <= 10000, 从中选出4个数要求gcd为1,这样的集合有多少个? 分析:首先总共集合nCr(n, 4) = n*(n-1)*(n ...
- linux和window下mkdir函数
通过WIN32宏进行判断 window下mkdir函数 #include<direct.h> int _mkdir( const char *dirname ); linux下 ...
- SQL Server Mobile 和 .NET 数据访问接口之间的数据类型映射
.NET 数据类型 SQL Server Mobile 数据类型 binary varbinary boolean bit byte tinyint byte[] varbinary dateti ...
- *JRebel 热部署
Jrebel是一套商业Java开发软件,可快速实现热部署,节省大量重启时间,提高开发效率. 去IDEA的插件官网下载插件:http://plugins.jetbrains.com/plugin/444 ...
- ActiveMQ之 TCP通讯机制
ActiveMQ支持多种通讯协议TCP/UDP等,我们选取最常用的TCP来分析ActiveMQ的通讯机制.首先我们来明确一个概念: 客户(Client):消息的生产者.消费者对ActiveMQ来说都 ...