Splay POJ3468(老题新做)

简介:
A Simple Problem with Integers
Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u
Appoint description:  System Crawler  (2014-11-12)

Description

You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C abc" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q ab" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.

这题应该算是线段树区间入目题目,只是还能够用Splay来做,用Splay来维护序列。用到了平衡二叉树的一个重要的性质那就是中序遍历是有序的。人生第一道Splay(感人TAT。QAQ)

代码例如以下:

/*************************************************************************
    > File Name: Spaly.cpp
    > Author: acvcla
    > QQ: 
    > Mail: acvcla@gmail.com 
    > Created Time: 2014年11月16日 星期日 00时14分26秒
 ************************************************************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<cstdlib>
#include<ctime>
#include<set>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 100;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
LL add[maxn],sum[maxn];
int ch[maxn][2],siz[maxn],key[maxn],pre[maxn],A[maxn];
int root,tot;
void newnode(int &x,int fa,int Key)//新建节点
{
	x=++tot;
	pre[x]=fa;
	siz[x]=1;
	key[x]=sum[x]=Key;
	ch[x][0]=ch[x][1]=add[x]=0;
}
void Modify(int x,int val){//区间更新
	if(!x)return;
	add[x]+=val;
	key[x]+=val;
	sum[x]+=(LL)val*siz[x];
}
void push_down(int x){//下传标记
	if(!add[x])return ;
	Modify(ch[x][0],add[x]);
	Modify(ch[x][1],add[x]);
	add[x]=0;
}
void push_up(int x){//更新节点
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
	sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+key[x];
}
void built(int &x,int L,int R,int fa){
	if(L>R)return;
	int M=(L+R)>>1;
	newnode(x,fa,A[M]);
	built(ch[x][0],L,M-1,x);
	built(ch[x][1],M+1,R,x);
	push_up(x);
}
void Init(int n)//初始化Spaly。加入了两个虚拟节点。便于提取区间,避免讨论
{
	root=tot=0;
	newnode(root,0,0);
	newnode(ch[root][1],root,0);
	for(int i=1;i<=n;i++)scanf("%d",A+i);
	built(ch[ch[root][1]][0],1,n,ch[root][1]);
	push_up(ch[root][1]);
	push_up(root);
}
void print(int x){
	if(!x)return;
	print(ch[x][0]);
	printf("%d ",key[x]);
	print(ch[x][1]);
}
void Rotate(int x,bool kind){//旋转,true右旋,false左旋
	int y=pre[x];
	push_down(y);//下传标记
	push_down(x);

	ch[y][!kind]=ch[x][kind];
	pre[ch[x][kind]]=y;
	ch[x][kind]=y;

	if(pre[y])ch[pre[y]][ch[pre[y]][1]==y]=x;//若y的父节点存在将其孩子指针指向x
	pre[x]=pre[y];
	pre[y]=x;
	push_up(y);//更新回来,须要注意的是。要先更新孩子
	push_up(x);
}
void Spaly(int x,int goal){//伸展操作。将x旋转到goal以下
	push_down(x);
	while(pre[x]!=goal){
		if(pre[pre[x]]==goal)Rotate(x,ch[pre[x]][0]==x);
		else{
			int y=pre[x];
			bool kind=(ch[pre[y]][0]==y);
			if(ch[y][kind]==x){
				Rotate(x,!kind);
				Rotate(x,kind);
			}else{
				Rotate(y,kind);
				Rotate(x,kind);
			}
		}
	}
	push_up(x);
	if(goal==0)root=x;//假设goal是0说明已经将x旋转到了根,所以要更新root
}
int Get_kth(int x,int k){//序列中的第k个值
	int t=siz[ch[x][0]]+1;
	if(t==k)return x;
	if(t>k)return Get_kth(ch[x][0],k);
	return Get_kth(ch[x][1],k-t);
}
int main(){
		ios_base::sync_with_stdio(false);
		cin.tie(0);
		siz[0]=sum[0]=0;//不存在的节点初始化为0避免讨论
		int n,q,l,r,x;
		scanf("%d%d",&n,&q);
		Init(n);
		char cmd[5];
		while(q--){
			scanf("%s%d%d",cmd,&l,&r);
			Spaly(Get_kth(root,l),0);
			Spaly(Get_kth(root,r+2),root);
			if(cmd[0]=='Q'){
				printf("%lld\n",sum[ch[ch[root][1]][0]]);
			}else{
				int Add;
				scanf("%d",&Add);
				Modify(ch[ch[root][1]][0],Add);
				push_up(ch[root][1]);
				push_up(root);
			}
		}
		return 0;
}







本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5239212.html,如需转载请自行联系原作者

相关文章
|
7月前
|
Java
POJ- 2367- Genealogical tree【拓扑排序】
POJ- 2367- Genealogical tree【拓扑排序】
25 0
|
7月前
|
算法 vr&ar Windows
Tarjan算法求LCA(最近公共祖先)
Tarjan算法求LCA(最近公共祖先)
43 0
|
算法 C++
最近公共祖先(LCA)
最近公共祖先(LCA)
60 0
牛客—— 小A的最短路 (LCA)
牛客—— 小A的最短路 (LCA)
93 0
树上倍增求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。 输入格式 第一行包含三个正整数 N,M,SN,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。 接下来 N-1N−1 行每行包含两个正整数 x, yx,y,表示 xx 结点和 yy 结点之间有一条直接连接的边(数据保证可以构成树)。 接下来 MM 行每行包含两个正整数 a, ba,b,表示询问 aa 结点和 bb 结点的最近公共祖先。
203 0
树上倍增求LCA
|
算法
LCA 最近公共祖先
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现     首先是最近公共祖先的概念(什么是最近公共祖先?):     在一棵没有环的树上,每个节点肯定有其父亲节点和祖先节点,而最近公共祖先,就是两个节点在这棵树上深度最大的公共的祖先节点。
1359 0