hdu2475Box(splay树形转线性)
推荐一篇帖子
http://blog.csdn.net/lyhypacm/article/details/6734748
这题暴力不可行主要是因为这颗树可能极度不平衡,不能用并查集是不能路径压缩,这样时间复杂度是很高的。
可以用伸展树主要是因为它的伸展性,每次操作后可以通过伸展使这棵树更好的保持平衡。
这题还是值得记录一下的,从早上做到了晚上,
第一次错误,定义了全局的n以及局部的n使得取得结果不正确,以后还是统一习惯,要么写在全局要么写在局部。
第二次错误,vector初始化没有初始到0导致后面的数据跑不动,以后初始化的操作都从0开始。
第三次错误,debug了n久,建树的时候误把根节点的父亲节点写成了根,应该是0,自以为不会出错的地方也要认真检查。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
using namespace std;
#define N 100010
#define LL long long
#define INF 0xfffffff
const double eps = 1e-;
const double pi = acos(-1.0);
const double inf = ~0u>>;
int n,po[N];
vector<int>ed[N];
vector<int>dd; struct splay_tree
{
int pre[N];
int ch[N][];
int root,tot,num;
int key[N];
// void dfs(int x)
// {
// if(x)
// {
// dfs(ch[x][0]);
// printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size=%2d,key=%2d\n",
// x,ch[x][0],ch[x][1],pre[x],size[x],key[x]);
// dfs(ch[x][1]);
// }
// }
// void debug()
// {
// printf("root:%d\n",root);
// dfs(root);
// }
//以上用于debug*/
void newnode(int &x,int v,int fa)//新建一结点
{
x = ++tot;
ch[x][]=ch[x][] = ;
pre[x] = fa;
key[x] = v;
po[v] = x;
}
void pushup(int w)//由儿子更新其父亲
{
}
void rotate(int r,int kind)//旋转操作,根据kind进行左旋和右旋
{
int y = pre[r];
ch[y][!kind] = ch[r][kind];
pre[ch[r][kind]] = y;
if(pre[y])
{
ch[pre[y]][ch[pre[y]][]==y] = r;
}
pre[r] = pre[y];
ch[r][kind] = y;
pre[y] = r;
pushup(y);
pushup(r);
}
void splay(int r,int goal)//将r结点旋至goal下
{
while(pre[r]!=goal)
{
if(pre[pre[r]]==goal)
{
rotate(r,ch[pre[r]][]==r);
}
else
{
int y = pre[r];
int kind = (ch[pre[y]][]==y);
if(ch[y][kind]==r)
{
rotate(r,!kind);
rotate(r,kind);
}
else
{
rotate(y,kind);
rotate(r,kind);
}
}
}
pushup(r);
if(goal==) root = r;
}
int get_min(int x)
{
while(ch[x][])
x = ch[x][];
return x;
}
int get_max(int x)
{
while(ch[x][])
x = ch[x][];
return x;
}
void update(int x,int y) //更新区间信息
{
int l = po[x],r = po[x+n];
splay(l,);
splay(r,);
int ll = ch[l][];
int rr = ch[r][];
pre[ll] = pre[rr] = ;
ch[r][] = ch[l][] = ; int tll = get_max(ll);
if(tll!=)
ch[tll][] = rr;
pre[rr] = tll; if(y==) return ;
if(query(y)==x)
{
ch[r][] = rr;
ch[l][] = ll;
pre[ll] = l;
pre[rr] = r;
ch[tll][] = ;
pre[] = ;
return ;
} if(rr!=) splay(rr,);
int tt = po[y];
splay(tt,);
int tq = get_min(ch[tt][]);
splay(tq,tt);
ch[tq][] = r;
pre[r] = tq;
}
int query(int x)//询问l,r区间,将第l-1个结点旋自根,第r+1个结点旋自根的有儿子,
{
splay(po[x],);
int k = get_min(po[x]);
return key[k];
}
void build(int &x,int l,int r,int fa)
{
int m = (l+r)>>;
if(l>r) return ;
newnode(x,dd[m],fa);
build(ch[x][],l,m-,x);
build(ch[x][],m+,r,x);
pushup(x);
}
void init()
{
root = tot = ;
memset(ch,,sizeof(ch));
memset(pre,,sizeof(pre));
memset(key,,sizeof(key));
memset(po,,sizeof(po));
}
} SP;
void dfs(int u)
{
int i;
dd.push_back(u);
for(i = ; i < ed[u].size(); i++)
{
int v = ed[u][i];
dfs(v);
}
dd.push_back(u+n);
}
int main()
{
int i;
int q;
int mark = false;
while(scanf("%d",&n)!=EOF)
{
if(mark)
puts("");
else
mark = true;
SP.init();
for(i = ; i <= n; i++)
{
ed[i].clear();
}
dd.clear();
for(i = ; i <= n; i++)
{
int x;
scanf("%d",&x);
ed[x].push_back(i);
}
dfs();
int o = ;
scanf("%d",&q);
stack<int>st;
for(i = ; i < dd.size()- ; i++)
{
int x = dd[i];
if(x<=n) st.push(x);
else st.pop();
if(st.empty())
{
SP.build(SP.root,o,i,);
o = i+;
}
}
int stt = ;
while(q--)
{
char sq[];
int x,y;
scanf("%s",sq);
if(sq[]=='Q')
{
scanf("%d",&x);
printf("%d\n",SP.query(x));
}
else
{
scanf("%d%d",&x,&y);
SP.update(x,y);
}
}
}
return ;
}
hdu2475Box(splay树形转线性)的更多相关文章
- Codeforces 570D - Tree Requests【树形转线性,前缀和】
http://codeforces.com/contest/570/problem/D 给一棵有根树(50w个点)(指定根是1号节点),每个点上有一个小写字母,然后有最多50w个询问,每个询问给出x和 ...
- CodeForces 466E Information Graph --树形转线性+并查集
题意:有三种操作: 1.新增一条边从y连向x,此前x没有父节点 2.x接到一份文件,(文件标号逐次递增),然后将这份文件一路上溯,让所有上溯的节点都接到这份文件 3.查询某个节点x是否接到过文件F 解 ...
- 线性结构与树形结构相互转换(ES6实现)
前言 当树形结构的层级越来越深时,操作某一节点会变得越来越费劲,维护成本不断增加.所以线性结构与树形的相互转换变得异常重要! 首先,我们约定树形结构如下: node = { id: number, / ...
- 第一阶段:Java内功秘籍-线性表
前言 为什么要学习数据结构与算法,如果你学会了做安卓,javaweb,前端等,都是你的武功秘籍,但是如果你的内功不够好,再厉害的功夫也是白费. 数据结构和算法:什么是数据结构,什么是数据,在计算机内部 ...
- RMQ 与 LCA-ST算法
RMQ算法 区间求最值的算法,用区间动态规划(nlogn)预处理,查询O(1) http://blog.csdn.net/y990041769/article/details/38405063 (PO ...
- 树链剖分详解(洛谷模板 P3384)
洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 emm还有必备的 链式前向星.线段树 也要先学了. 如果这三个知识点没掌握好的话,树链剖 ...
- Kuangbin 带你飞-线段树专题 题解
HDU 1166 敌兵布阵 单调更新区间查询和 #include <map> #include <set> #include <list> #include < ...
- git使用笔记-基础篇
git使用手册:https://git-scm.com/book/zh/v1/ 一.分支 1.查看所有本地分支 git branch 2.查看所有本地分支和远程分支 git branch -a 3.查 ...
- UVA10410 TreeReconstruction 树重建 (dfs,bfs序的一些性质,以及用栈处理递归 )
题意,给你一颗树的bfs序和dfs序,结点编号小的优先历遍,问你可能的一种树形: 输出每个结点的子结点. 注意到以下事实: (1)dfs序中一个结点的子树结点一定是连续的. (2)bfs,dfs序中的 ...
随机推荐
- 小工具之Synergy
用于两个主机共享键盘和鼠标的工具: 软件名字:synergy软件主页: http://synergy-foss.org支持平台:linux,mac,windows 通吃 作用:通过网络在多台主机之间共 ...
- Qt工程pro文件的简单配置(尤其是第三方头文件和库)
Qt开发中,pro文件是对正工程所有源码.编译.资源.目录等的全方位配置的唯一方式,pro文件的编写非常重要,以下对几个重要项进行说明(win和linux,mac平台通用配置) 注释 以”#”开始的行 ...
- python在三引号中使用变量
- AngularJS系统学习之$watch(监控)
在scope的内置的所有函数中,用的最多的可能就是$watch函数了, 当你的数据模型中某一部分发生变化时,$watch函数可以向你发出通知. 你可以监控单个对象的属性,亦可以监控需要经过计算的结果( ...
- cocos2d-x2.2+win7+vs2010+python安装配置
个人网站http://www.ravedonut.com/ 1.安装vs2010 2.解压cocos2d-x,打开cocos2d-win32.vc2012.sln,编译,然后运行Hellocpp成功即 ...
- 爬取动态网页:Selenium
参考:http://blog.csdn.net/wgyscsf/article/details/53454910 概述 在爬虫过程中,一般情况下都是直接解析html源码进行分析解析即可.但是,有一种情 ...
- Flex屏蔽并自定义鼠标右键菜单
http://www.cnblogs.com/wuhenke/archive/2010/01/29/1659353.html Google Code上有一个RightClickManager的项目. ...
- LeetCode: 292 Nim Game(easy)
题目: You are playing the following Nim Game with your friend: There is a heap of stones on the table, ...
- 牛客 - 17968 - xor序列 - 线性基
https://ac.nowcoder.com/acm/problem/17968 下面是错误的做法,因为题目要求必须使用x,而y在check的时候不一定用到等价于x的线性基来构成. 正确的做法是直接 ...
- 3DMAX 烘培技术
烘培是指,把光照信息渲染成贴图,而后把这个烘培后的贴图再贴回到场景中去的技术.烘培技术把光照计算的结果提前写入到了贴图中,因此在实时渲染中不需要进行耗时的光照计算,大大提高了实时渲染的效率. 烘培和渲 ...