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

2024-09-05 04:08

本文主要是介绍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); //LLR_rotate(X); //LL}else{R_rotate(X); //RLL_rotate(X);}}else{if(p == p->fa->r){ //RRL_rotate(p);L_rotate(X);}else{ //LRL_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;
}
















这篇关于Splay树(区间更新)—— POJ 3468 A Simple Problem with Integers的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1137907

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];