Splay POJ3468(老题新做)

A Simple Problem with Integers

Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d
& %I64u

Submit Status Practice POJ
3468

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: [email protected]
    > 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;
}
时间: 2024-12-16 17:25:58

Splay POJ3468(老题新做)的相关文章

老题新做,再战津津

又把一道很水的题来出来做了,就是2004年提高组津津的题,之前刚学循环的时候,一直没有看懂题面,不能搞懂循环点在哪,很迷很颓,就像一个心结一样压着,今天抽空又拿来看了一波,觉得很有搞头,于是在追求着一遍ac的前提下,不断拿样例调试,然后真的一遍A了,(突然兴奋) #include<stdio.h> #include<math.h> int flag[13]; int money[13]; int main () { int chuxuq = 0, chuxuh , chuxusum

旧题新做:从idy的视角看数据结构

“今天你不写总结……!!!” 额…… 还是讲我的吧.这些考试都是idy出的题. 20170121:DFS序. ST表.线段树练习 这是第一次考数据结构. Problem 1. setsum 1 second 给你一个长度为N 的整数序列,支持两种操作: • modity l r val 将区间[l,r] 中的所有数修改为val • query l r 询问区间[l,r] 所有数的和 分析:最简单的线段树,区间更改区间求和.但注意是更改,不是添改,sum与flag需同时覆盖. Problem 2.

# 清北冬令营真题泛做

清北冬令营真题泛做 前言 这段时间为了准备冬令营把清北冬令营真题都做了一下.更个博回顾一下(免得你们老说我咕咕咕). 先写良心PKU的题再写THU的题, 主要是THU的题和PKU比起来真的毒瘤好多...... PKUWC2018 [PKUWC2018]Minimax 一个比较显然的暴力是归并排序,每次直接前后缀计算答案即可. 为啥不用线段树合并代替归并排序呢? 暴力线段树合并,合并的过程中顺便算一下即可,由于权值区间不交所以复杂度一个\(log\). [PKUWC2018]Slay the Sp

历年NOIP水题泛做

快noip了就乱做一下历年的noip题目咯.. noip2014 飞扬的小鸟 其实这道题并不是很难,但是就有点难搞 听说男神错了一个小时.. 就是$f_{i,j}$表示在第$i$个位置高度为$j$的时候最小点击次数 递推的话对于上升的情况只做一次,后面几次在后面再做.. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace st

eclipse下配置tomcat、修改字体、为什么得运行两次才能实现新做的改动的问题

问题一: 手把手图文教你eclipse下如何配置tomcat 问题二: 用Eclipse做j2me工程为什么得运行两次才能实现新做的改动 这个问题简而言之:先保存再运行就可以一次实现了. 问题三: Eclipse怎样修改字体 我的是英文版的eclipse,所以是window -> preferences -> General -> Appearance -> Colors and Fonts   然后选择中是:Basic -> Text Font.

预热双十一,应用+老带新拿返利

老带新拿返利,万元奖金等你来赚! 活动用户:应用+VIP用户 活动时间:2015.11.1-2015.11.11活动奖励:凡VIP用户推荐新用户成功购买应用+的系列产品,新老客户可共享成交金额的10%现金奖励. 厦门创云科技有限公司保留对以上活动的最终解释权. 搭建手游联运平台当然首选应用+,行业顶尖的手游联运平台:炫酷的App原生客户端,一流的研发团队全程技术支持.您还在犹豫什么,快来加入我们吧!!!

(各个公司面试原题)在线做了一套CC++综合测试题,也来测一下你的水平吧(二)

刚才把最后的10道题又看了下,也发上来吧. 下面给出试题,和我对题目的一些理解 前10道题地址 (各个公司面试原题)在线做了一套CC++综合测试题,也来测一下你的水平吧(一) 11.设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为? C c; void main() { A*pa=new A(); B b; static D d; delete pa; } A.    A B C D B.    A B D C C.   A C D B D.   A C B D 答案:

第五届蓝桥杯C/C++本科B组(真题试做)(1~5)

菜鸡只能报个B组.于是报了第六届的本科B.就找了上届的本科B的题来做做. A: 标题:啤酒和饮料 啤酒每罐2.3元,饮料每罐1.9元.小明买了若干啤酒和饮料,一共花了82.3元. 我们还知道他买的啤酒比饮料的数量少,请你计算他买了几罐啤酒. 注意:答案是一个整数.请通过浏览器提交答案. 不要书写任何多余的内容(例如:写了饮料的数量,添加说明文字等). 对于这种,我直接暴力了. double a=2.3,b=1.9; FOR(j,0,SIZE) FOR(i,0,j) { if(abs(a*i+b*

问题:新做的一块板子,程序是一样的,网卡就是启动不了

新做的一块板子,程序是做到SD卡里面,全部自动烧录的,包括Uboot,Kernel,Filesystem:所以程序是一样的, 现在问题是,网卡启动不了: 查看Uboot的参数发现:ethaddr=00:00:00:00:00:00 然后进入系统后, ifconfig只有 lo        Link encap:Local Loopback inet addr:127.0.0.1  Mask:255.0.0.0 UP LOOPBACK RUNNING  MTU:16436  Metric:1 R