磨蹭了一下午+晚上,写了个指针版本的splay tree

http://poj.org/problem?id=3468

写完后发现用指针的速度比数组快了一秒。。。。。

等有空把那个维修数列也写一写试一下,不知道能跑多快

贴一下一个下午的成果吧,总感觉代码量上还可以精简,,,,求路过的神牛指导啊

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long lld;
#define L x->c[0]
#define R x->c[1]
#define KT root->c[1]->c[0]
const int maxn = 100010;
struct node {
	struct node *c[2] , *fa;
	int id ;
	int sz;
	int val;
	int add;
	lld sum;
	void down(){
		if(add) {
			if(c[0]) {
				c[0]->val += add;
				c[0]->add += add;
				c[0]->sum += (lld)add * c[0]->sz;
			} 
			if(c[1]) {
				c[1]->val += add;
				c[1]->add += add;
				c[1]->sum += (lld)add * c[1]->sz;
			}
			add = 0;
		}
	}
	void up() {
		sz = c[0]->sz + c[1]->sz + 1;
		sum= val + c[0]->sum + c[1]->sum;
	}
}*root,NODE[maxn],*null=&NODE[0];
int  num[maxn] , n , top; 
struct SplayTree{
	void Rotate(node *x,int f) {
		node *y = x->fa;
		y->down(); x->down();
		y->c[!f] = x->c[f];
		x->c[f]->fa = y;
		x->fa = y->fa;
		if(x->fa != null) y->fa->c[ y->fa->c[1] == y ] = x;  
		x->c[f] = y;
		y->fa = x;
		y->up();
	}
	void Splay(node *x,node *goal) {
		x->down();
		while(x->fa != goal) {
			if(x->fa->fa == goal) Rotate(x,x->fa->c[0] == x);
			else {
				node *y = x->fa , *z = y->fa;
				int f = (z->c[0] == y);
				y->c[f]==x ? Rotate(x,!f) :Rotate(y,f);
				Rotate(x,f);
			}
		}
		x->up();
		if(goal == null) root = x;
	}
	void RTO(int k,node *goal) {
		node *x = root;
		x->down();
		while(L->sz + 1 != k) {
			if(k < L->sz + 1) x = L;
			else{
				k -= L->sz + 1;
				x = R;
			}
			x->down();
		}
		Splay(x,goal);
	}
	node *new_node(node *fa,int v) {
		node *x=&NODE[++top];
		x->id = top;
		x->c[0] = x->c[1] = null;
		x->sz = 1;
		x->val = x->sum = v;
		x->add = 0;
		x->fa = fa;
		return x;
	}
	void build(node* &x,int l,int r,node *fa) {
		if(l > r) return ;
		int m = l + r>>1;
		x = new_node(fa,num[m]);
		build(x->c[0],l,m-1,x);
		build(x->c[1],m+1,r,x);
		x->up();
	}
	void vist(node *x) {
		if(x!=null){
			printf("节点:%2d : 左儿子: %2d  右儿子:  %2d  sz: %2d sum: %2lld\n",
				x->id,x->c[0]->id,x->c[1]->id,x->sz,x->sum);
			vist(x->c[0]);
			vist(x->c[1]);
		}
	}
	void init(int n) {
		top = 0;
		null->id = 0;
		null->c[0] = null->c[1] = null->fa = NULL;
		null->sz =  null->add = null->sum = null->val = 0;
		root = new_node(null,-1);
		root->c[1] = new_node(root,-1);
		root->sz = 2;
		for(int i = 1; i <= n; i++) scanf("%d",&num[i]);
		build(KT,1,n,root->c[1]);
		root->c[1]->up(); root->up();
	}		
	void update(){
		int l ,r , c;
		scanf("%d%d%d",&l,&r,&c);
		RTO(l,null);
		RTO(r+2,root);
		KT->add += c;
		KT->val += c;
		KT->sum += (lld)c * KT->sz;
	}
	void query() {
		int l ,r ;
		scanf("%d%d",&l,&r);
		RTO(l,null);
		RTO(r+2,root);
		printf("%I64d\n",KT->sum);
	}
}spt;
int main() {
	char op[10];
	int m;
	scanf("%d%d",&n,&m);
	spt.init(n);
	for(int i=0;i<m;i++) {
		scanf("%s",op);
		if(op[0] == 'Q')spt.query();
		else spt.update();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值