POJ3468

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100010
#define inf 0x3f3f3f3f
#define LL long long int
#define Key_value ch[ch[root][1]][0]
int pre[maxn],key[maxn],ch[maxn][2],root,tot1;
int size[maxn],s[maxn],tot2,val[maxn];
int add[maxn];
LL sum[maxn];
int n,q;
void NewNode(int & r,int father,int k)
{
	if(tot2)
		r = s[--tot2];
	else 
		r = ++tot1;
	pre[r] = father;
	val[r] = k;
	sum[r] = k;
	add[r] = 0;
	size[r] = 1;
	ch[r][0] = ch[r][1] = 0;
}

//将延迟标记更新到孩子结点
void PushDown(int r)
{
	if(add[r])
	{
		val[r] += add[r];
		add[ch[r][0]] += add[r];
		add[ch[r][1]] += add[r];
		sum[ch[r][0]] += (LL)add[r]*size[ch[r][0]];
		sum[ch[r][1]] += (LL)add[r]*size[ch[r][1]];
		add[r] = 0;
	}
}

//通过孩子结点更新父结点
void PushUp(int r)
{
	size[r] = size[ch[r][0]] + size[ch[r][1]] + 1;
	sum[r] = sum[ch[r][0]] + sum[ch[r][1]] + val[r] + add[r];
}

//旋转,kind为1为右旋,kind为0为左旋
void Rotate(int x,int kind)
{
	int y = pre[x];
	PushDown(y);
	PushDown(x);
	//类似SBT,要把其中一个分支先给父结点
	ch[y][!kind] = ch[x][kind];
	pre[ch[x][kind]] = y;
	//如果父结点不是根结点,则要和父结点的父结点连接起来
	if(pre[y])
		ch[pre[y]][ch[pre[y]][1] == y] = x;
	pre[x] = pre[y];
	ch[x][kind] = y;
	pre[y] = x;
	PushUp(y);
	//PushUp(x);
}

void Splay(int r,int goal)
{
	PushDown(r);
	while(pre[r] != goal)
	{
		//父结点即是目标位置,goal为0表示,父结点就是根节点
		if(pre[pre[r]] == goal)
			Rotate(r,ch[pre[r]][0]==r);
		else
		{
			int y = pre[r];
			int kind = ch[pre[y]][0] == y;
			//两个方向不同,则先左旋再右旋
			if(ch[y][kind] == r)
			{
				Rotate(r,!kind);
				Rotate(r,kind);
			}
			//两个方向相同,相同方向连续两次
			else 
			{
				Rotate(y,kind);
				Rotate(r,kind);
			}
		}
	}
	PushUp(r);
	//更新根节点
	if(goal == 0)	root = r;
}

//把第k位的数转到goal下边
void RotateTo(int k,int goal)
{
	int r = root;
	PushDown(r);
	while(size[ch[r][0]] != k)
	{
		if(k < size[ch[r][0]])
			r = ch[r][0];
		else 
		{
			k -= (size[ch[r][0]] + 1);
			r = ch[r][1];
		}
		PushDown(r);
	}
	Splay(r,goal);
}

int Insert(int k)
{
	int r = root;
	while(ch[r][key[r]<k])
		r = ch[r][key[r] < k];
	NewNode(ch[r][k>key[r]],r,k);
	Splay(ch[r][k>key[r]],0);
	return 1;
}

//找前驱,即左子树的最右结点
int get_pre(int x)
{
	int tmp = ch[x][0];
	if(tmp == 0)	return inf;
	while(ch[tmp][1])
		tmp = ch[tmp][1];
	return key[x] - key[tmp];
}

//找后继,即右子树的最左结点
int get_next(int x)
{
	int tmp = ch[x][1];
	if(tmp == 0)	return inf;
	while(ch[tmp][0])
		tmp = ch[tmp][0];
	return key[tmp] - key[x];
}

//查询[l,r]之间的和
LL Query(int l,int r)
{
	RotateTo(l-1,0);
	RotateTo(r+1,root);
	return sum [Key_value];
}

//更新
void Update(int l,int r)
{
	int k;
	scanf("%d",&k);
	RotateTo(l-1,0);
	RotateTo(r+1,root);
	add[Key_value] += k;
	sum[Key_value] += size[Key_value]*k;
}

int a[maxn];
//建树,中间结点先建立,然后分别对区间两端在左右子树建立
void BuildTree(int &x,int l,int r,int father)
{
	if(l > r)
		return;
	int mid = (l+r)/2;
	NewNode(x,father,a[mid]);
	if(l < mid)
		BuildTree(ch[x][0],l,mid-1,x);
	if(r > mid)
		BuildTree(ch[x][1],mid+1,r,x);
	PushUp(x);
}

void Init()
{
	for(int i = 0;i < n;i++)
		scanf("%d",&a[i]);
	ch[0][0] = ch[0][1] = pre[0] = size[0] = 0;
	add[0] = sum[0] = 0;
	root = tot1 = 0;
	NewNode(root,0,-1);
	NewNode(ch[root][1],root,-1);
	size[root] = 2;
	BuildTree(Key_value,0,n-1,ch[root][1]);//让所有数据夹在两个-1之间
	PushUp(ch[root][1]);
	PushUp(root);
}

int main()
{
	while(scanf("%d%d",&n,&q)!=EOF)
	{
		Init();
		while(q--)
		{
			char str[10];
			int x,y;
			scanf("%s%d%d",str,&x,&y);
			if(str[0] == 'Q')
				printf("%lld\n",Query(x,y));
			else 
				Update(x,y);
		}
	}
	return 0;
}



风格更新后:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 100010
#define LL long long int
#define Key_value ch[ch[root][1]][0]

inline int min(int a,int b)
{
	return a>b?b:a;
}

struct SplayTree
{
	int pre[maxn],key[maxn],ch[maxn][2],size[maxn],add[maxn],a[maxn],root,cnt;
	LL sum[maxn];
	void init(int n)
	{
		root = cnt = 0;
		ch[0][0] = ch[0][1] = pre[0] = size[0] = key[0] = 0;
		add[0] = sum[0] = 0;
		NewNode(root,0,-1);
		NewNode(ch[root][1],root,-1);
		size[root] = 2;
		BuildTree(Key_value,0,n-1,ch[root][1]);
		PushUp(ch[root][1]);
		PushUp(root);
	}

	void BuildTree(int & x,int l,int r,int father)
	{
		if(l > r)	return;
		int mid = (l+r) >> 1;
		NewNode(x,father,a[mid]);
		if(l < mid)
			BuildTree(ch[x][0],l,mid-1,x);
		if(r > mid)
			BuildTree(ch[x][1],mid+1,r,x);
		PushUp(x);
	}
	
	void NewNode(int & r,int father,int k)
	{
		r = ++cnt;
		pre[r] = father;
		ch[r][0] = ch[r][1] = 0;
		key[r] = sum[r] = k;
		add[r] = 0;
		size[r] = 1;
	}

	void PushDown(int r)
	{
		if(add[r])
		{
			key[r] += add[r];
			add[ch[r][0]] += add[r];
			add[ch[r][1]] += add[r];
			sum[ch[r][0]] += (LL)add[r]*size[ch[r][0]];
			sum[ch[r][1]] += (LL)add[r]*size[ch[r][1]];
			add[r] = 0;
		}
	}

	void PushUp(int r)
	{
		size[r] = size[ch[r][0]] + size[ch[r][1]] + 1;
		sum[r] = sum[ch[r][0]] + sum[ch[r][1]] + key[r] + add[r];
	}

	void Rotate(int x,int kind)
	{
		int y = pre[x];
		PushDown(y);
		PushDown(x);
		ch[y][!kind] = ch[x][kind];
		pre[ch[x][kind]] = y;
		if(pre[y])
			ch[pre[y]][ch[pre[y]][1]==y] = x;
		pre[x] = pre[y];
		ch[x][kind] = y;
		pre[y] = x;
		PushUp(y);
	}
	
	void Splay(int r,int goal)
	{
		while(pre[r] != goal)
		{
			int y = pre[r],z = pre[y];
			PushDown(z);	PushDown(y);	PushDown(r);
			if(pre[pre[r]] == goal)
			{
				Rotate(r,ch[pre[r]][0]==r);
			}
			else 
			{
				int y = pre[r];
				int kind = ch[pre[y]][0] == y;
				if(ch[y][kind] == r)
				{
					Rotate(r,!kind);
				}
				else
				{
					Rotate(y,kind);
					Rotate(r,kind);
				}
			}
		}
		PushUp(r);
		if(goal == 0)	root = r;
	}

	void RotateTo(int k,int goal)
	{
		int r = root;
		PushDown(r);
		while(size[ch[r][0]] != k)
		{
			if(k < size[ch[r][0]])
				r = ch[r][0];
			else
			{
				k -= (size[ch[r][0]] + 1);
				r = ch[r][1];
			}
			PushDown(r);
		}
		Splay(r,goal);
	}

	void Update(int l,int r)
	{
		int k;
		scanf("%d",&k);
		RotateTo(l-1,0);
		RotateTo(r+1,root);
		add[Key_value] += k;
		sum[Key_value] += size[Key_value]*k;
	}

	LL Query(int l,int r)
	{
		RotateTo(l-1,0);
		RotateTo(r+1,root);
		return sum[Key_value];
	}

	void solve(int n,int q)
	{
		for(int i = 0;i < n;i++)
		{
			scanf("%d",&a[i]);
		}
		init(n);
		while(q--)
		{
			char str[10];
			int x,y;
			scanf("%s%d%d",str,&x,&y);
			if(str[0] == 'Q')
				printf("%lld\n",Query(x,y));
			else Update(x,y);
		}
	}
}spt;

int main()
{
	int n,q;
	while(scanf("%d%d",&n,&q)!=EOF)
	{
		spt.solve(n,q);
	}
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值