Splay树(区间更新)—— POJ 3468 A Simple Problem with Integers

对应POJ 题目:点击打开链接

A Simple Problem with Integers

Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 72765   Accepted: 22465
Case Time Limit: 2000MS

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 a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.

"Q a b" 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.

题意:

输入n,m;表示有n个数和m个询问。接着输入每个数的初始值。接着每个询问表示:Q表示求解i,j区间的和,C表示i~j区间的每个值都+k

思路:

Splay树区间更新问题,注意在更新标记后向上更新。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAX(x, y) ((x) > (y) ? (x) : (y))

typedef struct TREE
{
    long long sum; //以该结点为根的树的元素和
    TREE *fa, *l, *r;
    int sz; //以该结点为根的树的总结点数
	int add; //懒惰标记
}Tree;

void Push_down(Tree *T)
{
    if(NULL == T) return;
    if(T->add){
		T->sum += ((long long)(T->sz) * T->add);
        if(T->l) T->l->add += T->add;
        if(T->r) T->r->add += T->add;
        T->add = 0;
    }
}

void Init(Tree *&T, int n)
{
    int i;
	long long a;
    Tree *cur, *pre;
	pre = (Tree *)malloc(sizeof(Tree));
	pre->sum = 0;
	pre->fa = pre->l = pre->r = NULL;
	pre->sz = 1;
	pre->add = 0;
    for(i = n - 1; i > -1; i--){
        cur = (Tree *)malloc(sizeof(Tree));
		scanf("%I64d", &a);
		cur->l = pre;
		cur->r = NULL;
		pre->fa = cur;
		cur->sz = pre->sz + 1;
		cur->sum = a + pre->sum;
		cur->add = 0;
        pre = cur;
		if(0 == i){
        	cur = (Tree *)malloc(sizeof(Tree));
			cur->fa = NULL;
			cur->l = pre;
			cur->r = NULL;
			pre->fa = cur;
			cur->sz = pre->sz + 1;
			cur->sum = pre->sum;
			cur->add = 0;
		}
    }
    T = cur;
}

void R_rotate(Tree *x)
{
    Tree *y = x->fa;
    Tree *z = y->fa;
    Tree *k = x->r;
    int sx = x->sz, sy = y->sz, sk = 0;
    long long sumx = x->sum, sumy = y->sum, sumk = 0;
    if(k){
		Push_down(k);
		sk = k->sz;
		sumk = k->sum;
	}
    y->l = k;
    x->r = y;
    if(z){
        if(y == z->l) z->l = x;
        else z->r = x;
    }
    if(k) k->fa = y;
    y->fa = x;
    x->fa = z;
    y->sz = sy - sx + sk;
    x->sz = sx - sk + y->sz;
    y->sum = sumy - sumx + sumk;
    x->sum = sumx - sumk + y->sum;
}

void L_rotate(Tree *x)
{
    Tree *y = x->fa;
    Tree *z = y->fa;
    Tree *k = x->l;
    int sx = x->sz, sy = y->sz, sk = 0;
    long long sumx = x->sum, sumy = y->sum, sumk = 0;
    if(k){
		Push_down(k);
		sk = k->sz;
		sumk = k->sum;
	}
    y->r = k;
    x->l = y;
    if(z){
        if(y == z->r) z->r = x;
        else z->l = x;
    }
    if(k) k->fa = y;
    y->fa = x;
    x->fa = z;
    y->sz = sy - sx + sk;
    x->sz = sx - sk + y->sz;
    y->sum = sumy - sumx + sumk;
    x->sum = sumx - sumk + y->sum;
}

//寻找第x个数的结点
Tree *FindTag(Tree *T, int x)
{
    if(NULL == T) return NULL;
    Push_down(T);
    Tree *p;
    p = T;
    int sum = (p->l ? p->l->sz : 0) + 1;
    while(sum != x && p)
    {
        if(sum < x){
            p = p->r;
            x -= sum;
        }
        else p = p->l;
        Push_down(p);
        sum = (p->l ? p->l->sz : 0) + 1;
    }
    return p;
}

void Splay(int x, Tree *&T)
{
    Push_down(T);
    Tree *p, *X, *end, *new_t;
    end = T->fa;
    new_t = T;
    if(end) new_t = T->fa;
    X = FindTag(new_t, x);
    while(X->fa != end)
    {
        p = X->fa;
        if(end == p->fa){ //p是根结点
            if(X == p->l) R_rotate(X);
            else L_rotate(X);
            break;
        }
        //p不是根结点
        if(X == p->l){
            if(p == p->fa->l){
                R_rotate(p); //LL
                R_rotate(X); //LL
            }
            else{
                R_rotate(X); //RL
                L_rotate(X);
            }
        }
        else{
            if(p == p->fa->r){ //RR
                L_rotate(p);
                L_rotate(X);
            }
            else{ //LR
                L_rotate(X);
                R_rotate(X);
            }
        }
    }
    T = X;
}

void FreeTree(Tree *T)
{
    if(NULL == T) return;
    FreeTree(T->l);
    FreeTree(T->r);
    free(T);
}

void InOrder(Tree *T)
{
	if(NULL == T) return;
	Push_down(T);
	InOrder(T->l);
	printf("%d ", T->sum);
	InOrder(T->r);
}

int main()
{
    //freopen("in.txt", "r", stdin);
    Tree *T;
	T = NULL;
	int n, q;
	int a, b, c;
	char s[3];
	scanf("%d%d", &n, &q);
	Init(T, n);
	while(q--)
	{
		//InOrder(T);
		//printf("\n");
		scanf("%s", s);
		if('Q' == s[0]){
			scanf("%d%d", &a, &b);
			a++; b++;
			Splay(a - 1, T);
			Splay(b + 1, T->r);
			Push_down(T->r->l);
			printf("%I64d\n", T->r->l->sum);
		}
		else{
			scanf("%d%d%d", &a, &b, &c);
			a++; b++;
			Splay(a - 1, T);
			Splay(b + 1, T->r);
			T->r->l->add += c;
			//向上更新
			T->r->sum += ((long long)(b - a + 1) * c);
			T->sum += ((long long)(b - a + 1) * c);
		}
	}
	FreeTree(T);
    return 0;
}
时间: 2024-10-11 17:48:31

Splay树(区间更新)—— POJ 3468 A Simple Problem with Integers的相关文章

线段树 区间求和 poj 3468 A Simple Problem with Integers

题意: 给n个整数,求两种操作:1.给一个区间的数都加上一个数 2.查询一个区间的数的和  ,输出每次查询的结果 线段树区间求和,注意点: 1.使用lazy操作pushdown的时候,应该是子节点的lazy值加上父节点的lazy值,而不是直接赋值成父节点的lazy值,因为子节点可能之前也被操作过 2.节点的sum求和的时候应该加上区间的和(虽然直接加上修改值也能过样例TAT) 3.sum应该用long long 代码: #include <cstdlib> #include <cctyp

线段树(成段更新) POJ 3468 A Simple Problem with Integers

题目传送门 1 /* 2 线段树-成段更新:裸题,成段增减,区间求和 3 注意:开long long:) 4 */ 5 #include <cstdio> 6 #include <iostream> 7 #include <algorithm> 8 #include <cstring> 9 #include <cmath> 10 using namespace std; 11 12 #define lson l, mid, rt <<

POJ 3468 A Simple Problem with Integers(线段树区间更新)

题目地址:POJ 3468 打了个篮球回来果然神经有点冲动..无脑的狂交了8次WA..居然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题.区间更新就是加一个lazy标记,延迟标记,只有向下查询的时候才将lazy标记向下更新.其他的均按线段树的来就行. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <math.h> #include <stac

POJ 3468 A Simple Problem with Integers(线段树 区间更新)

Description You have N integers, A1, A2, ... , 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. In

poj 3468 A Simple Problem with Integers 【线段树-成段更新】

题目:poj 3468 A Simple Problem with Integers 题意:给出n个数,两种操作 1:l -- r 上的所有值加一个值val 2:求l---r 区间上的和 分析:线段树成段更新,成段求和 树中的每个点设两个变量sum 和 num ,分别保存区间 l--r 的和 和l---r 每个值要加的值 对于更新操作:对于要更新到的区间上面的区间,直接进行操作 加上 (r - l +1)* val .下面的区间标记num += val 对于求和操作,每次进行延迟更新,把num值

poj 3468:A Simple Problem with Integers(线段树,区间修改求和)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 58269   Accepted: 17753 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

poj 3468 A Simple Problem with Integers (线段树 成段更新 加值 求和)

题目链接 题意: 只有这两种操作 C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000."Q a b" means querying the sum of Aa, Aa+1, ... , Ab. 分析:自己写的有点麻烦了,写的时候手残+脑残,改了好久. val+lazy*(r-l+1)表示和,如果lazy==0表示当前区间加的值不统一. 1 #include <iostream

POJ 3468 A Simple Problem with Integers(线段树)

题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 56005   Accepted: 16903 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with

POJ 3468 A Simple Problem with Integers 【树状数组】

题目链接:http://poj.org/problem?id=3468 题目大意:给出一组数组v[i],有两种操作,一种给出两个数a,b,要求输出v[a]到v[b]之间的和,另一种给出三个数a,b,c,让v[a]到v[b]之间的数全都加上c. 完全是树状数组能够实现的功能,但是如果就这样单纯的套用模板,做第二种操作是更新每个值,这样的操作就有可能超时. 换一种思路,既然第二种操作是给某区间上的所有数加上相同的值,那么应该是能够简化的才对. 假设数组sum[i]为原数组从v[1]到v[i]的和,数

POJ - 3468 A Simple Problem with Integers (区间求和)

Description You have N integers, A1, A2, ... , 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. In