POJ-3468 A Simple Problem with Integers Splay Tree区间练习
题目链接:http://poj.org/problem?id=3468
以前用线段树做过,现在用Splay Tree A了,向HH、kuangbin、cxlove大牛学习了各种Splay各种操作,,,Orz。。
Splay Tree的区间操作和线段树的操作差不多,也是保存子树的值,然后懒惰操作,在Rotate()最后维护节点信息的时候,只要Push_Up(y)的,因为x还需要网上旋转到根节点,最后更新下就可以了,并且在下一次Rotate()的时候,还会Push_Down(x)的信息,因此不能Push_Up(x)。
//STATUS:C++_AC_3407MS_3696KB
#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],key[N],ch[N][]; //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
int sz[N],st[N]; //子树规模,内存池
int root,tot,top; //根节点,根节点数量,内存池容量
//题目特定数据
int num[N];
int val[N];
int add[N];
LL sum[N];
int n,m;
//debug部分copy from hh
void Treaval(int x) {
if(x) {
Treaval(ch[x][]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d , sum = %2d \n",x,ch[x][],ch[x][],pre[x],sz[x],val[x],sum[x]);
Treaval(ch[x][]);
}
}
void debug() {printf("%d\n",root);Treaval(root);}
//以上Debug
//新建一个结点
void NewNode(int &x,int fa,int k)
{
if(top)x=st[--top];
else x=++tot;
pre[x]=fa;
sz[x]=;
val[x]=k;
add[x]=;
sum[x]=k;
ch[x][]=ch[x][]=; //左右孩子为空
} void Push_Up(int x)
{
sz[x]=sz[ch[x][]]+sz[ch[x][]]+;
sum[x]=sum[ch[x][]]+sum[ch[x][]]+val[x];
} void Push_Down(int x)
{
if(add[x]){
val[x]+=add[x];
add[ch[x][]]+=add[x];
add[ch[x][]]+=add[x];
sum[ch[x][]]+=(LL)add[x]*sz[ch[x][]];
sum[ch[x][]]+=(LL)add[x]*sz[ch[x][]];
add[x]=;
}
} //旋转,kind为1为右旋,kind为0为左旋
void Rotate(int x,int kind)
{
int y=pre[x],z=pre[y];
Push_Down(y);
Push_Down(x); //先把y的标记向下传递,再把x的标记往下传递
//类似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,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;
} void RotateTo(int k,int goal)
{
int x=root;
Push_Down(x);
while(sz[ch[x][]]!=k){
if(sz[ch[x][]]>k)
x=ch[x][];
else {
k-=sz[ch[x][]]+;
x=ch[x][];
}
Push_Down(x);
}
Splay(x,goal);
} int Insert(int k)
{
int x=root;
while(ch[x][k>key[x]]){
//不重复插入
if(key[x]==k){
Splay(x,);
return ;
}
x=ch[x][k>key[x]];
}
NewNode(ch[x][k>key[x]],x,k);
//将新插入的结点更新至根结点
Splay(ch[x][k>key[x]],);
return ;
}
//找前驱,即左子树的最右结点
int Get_Pre(int x)
{
if(!ch[x][])return -INF;
x=ch[x][];
while(ch[x][])x=ch[x][];
return key[x];
}
//找后继,即右子树的最左结点
int Get_Suf(int x)
{
if(!ch[x][])return INF;
x=ch[x][];
while(ch[x][])x=ch[x][];
return key[x];
}
//建树,中间结点先建立,然后分别对区间两端在左右子树建立
void BuildTree(int &x,int l,int r,int fa)
{
if(l>r)return;
int mid=(l+r)>>;
NewNode(x,fa,num[mid]);
BuildTree(ch[x][],l,mid-,x);
BuildTree(ch[x][],mid+,r,x);
Push_Up(x);
} void Init()
{
ch[][]=ch[][]=pre[]=sz[]=;
add[]=sum[]=;
root=top=tot=;
NewNode(root,,-);
NewNode(ch[root][],root,-); //头尾各加入一个空位
sz[root]=; for(int i=;i<n;i++)
scanf("%d",&num[i]);
BuildTree(Key_value,,n-,ch[root][]); //让所有数据夹在两个-1之间
Push_Up(ch[root][]);
Push_Up(root);
} void Update(int a,int b,int c)
{
RotateTo(a-,);
RotateTo(b+,root);
add[Key_value]+=c;
sum[Key_value]+=sz[Key_value]*c;
} LL Query(int a,int b)
{
RotateTo(a-,);
RotateTo(b+,root);
return sum[Key_value];
} int main()
{
// freopen("in.txt","r",stdin);
int i,j,a,b,c;
char op[];
while(~scanf("%d%d",&n,&m))
{
Init();
while(m--){
scanf("%s",op);
if(op[]=='Q'){
scanf("%d%d",&a,&b);
printf("%I64d\n",Query(a,b));
}
else {
scanf("%d%d%d",&a,&b,&c);
Update(a,b,c);
}
}
}
return ;
}
POJ-3468 A Simple Problem with Integers Splay Tree区间练习的更多相关文章
- POJ 3468 A Simple Problem with Integers (splay tree入门)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 47944 ...
- poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和
A Simple Problem with Integers Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?i ...
- poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和(模板)
A Simple Problem with Integers Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?i ...
- [POJ] 3468 A Simple Problem with Integers [线段树区间更新求和]
A Simple Problem with Integers Description You have N integers, A1, A2, ... , AN. You need to deal ...
- poj 3468 A Simple Problem with Integers 线段树区间更新
id=3468">点击打开链接题目链接 A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072 ...
- poj 3468 A Simple Problem with Integers (线段树区间更新求和lazy思想)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 75541 ...
- POJ 3468 A Simple Problem with Integers(线段树,区间更新,区间求和)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 67511 ...
- POJ 3468 A Simple Problem with Integers(线段树区间更新)
题目地址:POJ 3468 打了个篮球回来果然神经有点冲动. . 无脑的狂交了8次WA..竟然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题. 区间更新就是加一个lazy标记,延迟标记, ...
- POJ 3468 A Simple Problem with Integers 线段树区间修改
http://poj.org/problem?id=3468 题目大意: 给你N个数还有Q组操作(1 ≤ N,Q ≤ 100000) 操作分为两种,Q A B 表示输出[A,B]的和 C A B ...
随机推荐
- 排队(BZOJ1731:[Usaco2005 dec]Layout 排队布局)
[问题描述] Czy喜欢将他的妹子们排成一队.假设他拥有N只妹纸,编号为1至N.Czy让他们站成一行,等待自己来派送营养餐.这些妹纸按照编号大小排列,并且由于它们都很想早点吃饭,于是就很可能出现多只妹 ...
- 设置BootStrap导航条的高度
只要加上这段css就可以覆盖Bootstrap.css的代码,定制符合自己的样式 .navbar { min-height: 40px; } .nav > li > a { padding ...
- 使用代理下载Android SDK
hx.gy:1080是红杏公益服务器,方便科学工作者访问一些常用的科学网站. 在Android SDK Manager中选择[Tools]->[Options],如下设置: HTTP Proxy ...
- python 内建函数 filter,map和reduce
python 内建函数 filter,map和reduce, 三个函数比较类似,都是应用于序列的内置函数,常见的序列包括list.tuple.str等.而且三个函数都可以和lambda表达式结合使用. ...
- Java编程思想(2)之一切皆对象
- [线段树]HDOJ5091 Beam Cannon
题意:给n, w, h (1 <= N <= 10000,1 <= W <= 40000,1 <= H <= 40000) $w\times h$是可以射到的范围 ...
- UVA 10765 Doves and bombs
给定一个无向的连通图,要求每个点去掉后连通分量的数目,然后输出连通分量最多的m个点. 分析: 先求出双连通分量,然后统计所有双连通分量中割顶出现的次数,最后求出的就是割顶去掉后剩下的双连通的数目,对于 ...
- table 表头固定
<html> <head> <title>Test</title> <style type="text/css"> .d ...
- [jobdu]不用加减乘除做加法
使用异或和与,模拟机器的加法.http://blog.csdn.net/htyurencaotang/article/details/11125415 #include <iostream> ...
- 以编程方式使用 Word 中的内置对话框
使用 Microsoft Office Word 时,有时需要显示用户输入对话框.虽然可以创建自己的对话框,您也许还希望采用使用 Word 中内置对话框的方法,这些对话框在Application 对象 ...