【Splay】洛谷3372 【模板】线段树 1

Splay区间加,询问区间和。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 100010
#define INF 2147483647
int fa[maxn],val[maxn],c[maxn][2],root,tot,siz[maxn];
ll lazy[maxn],totalval2[maxn],val2[maxn];
void Maintain(int x)
{
	siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;
	totalval2[x]=totalval2[c[x][0]]+totalval2[c[x][1]]+val2[x];
}
void mark(int x,ll delta){
	if(x){
		lazy[x]+=delta;
		totalval2[x]+=(ll)siz[x]*delta;
		val2[x]+=delta;
	}
}
void pushdown(int x){
	if(lazy[x]){
		mark(c[x][0],lazy[x]);
		mark(c[x][1],lazy[x]);
		lazy[x]=0;
//		Maintain(x);
	}
}
void NewNode(int &x,int Fa,int key,ll key2)
{
	x=++tot;
	fa[x]=Fa;
	c[x][0]=c[x][1]=0;
	val[x]=key;
	val2[x]=totalval2[x]=key2;
	siz[x]=1;
}
void Rotate(int x,bool flag)
{
	int y=fa[x];
	pushdown(y);
	pushdown(x);
	c[y][!flag]=c[x][flag];
	fa[c[x][flag]]=y;
	if(fa[y]){
		c[fa[y]][c[fa[y]][1]==y]=x;
	}
	fa[x]=fa[y];
	c[x][flag]=y;
	fa[y]=x;
	Maintain(y);
}
void Splay(int x,int goal)
{
	if(!x || x==goal){
		return;
	}
	pushdown(x);
	int y;
	while((y=fa[x])!=goal){
		if(fa[y]==goal){
			Rotate(x,c[y][0]==x);
		}
		else{
			if((c[y][0]==x)==(c[fa[y]][0]==y)){
				Rotate(y,c[fa[y]][0]==y);
			}
		  	else{
				Rotate(x,c[y][0]==x);
				y=fa[x];
			}
			Rotate(x,c[y][0]==x);
		}
	}
	Maintain(x);
	if(!goal){
		root=x;
	}
}
int Find(int key,int x=root)
{
    while(c[x][val[x]<key]){
        if(val[x]==key){
            return x;
        }
        x=c[x][val[x]<key];
    }
    return x;
}
void Insert(int key,ll key2)
{
    if(!root){
        NewNode(root,0,key,key2);
        return;
    }
    int x=Find(key);
    NewNode(c[x][val[x]<key],x,key,key2);
    Splay(c[x][val[x]<key],0);
}
int n,m;
int main(){
	int op,x,y;
	ll z;
	scanf("%d%d",&n,&m);
	Insert(0,1ll);
	for(int i=1;i<=n;++i){
		scanf("%lld",&z);
		Insert(i,z);
	}
	Insert(n+1,1ll);
	for(;m;--m){
		scanf("%d%d%d",&op,&x,&y);
		Splay(x,0);
		Splay(y+2,x);
		if(op==1){
			scanf("%lld",&z);
			mark(c[y+2][0],z);
		}
		else{
			printf("%lld\n",totalval2[c[y+2][0]]);
		}
	}
	return 0;
}
时间: 2024-07-31 14:22:30

【Splay】洛谷3372 【模板】线段树 1的相关文章

线段树_区间加乘(洛谷P3373模板)

题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字的个数.操作的总个数和模数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k 操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

AC自动机(附洛谷P3769模板题)

首先,介绍一下AC自动机(Aho-Corasick automaton),是一种在一个文本串中寻找每一个已给出的模式串的高效算法. 在学习AC自动机之前,你需要先学习Trie树和KMP算法,因为AC自动机正式利用并结合了两者的思想. 说到实际的不同,其实AC自动机只是在Trie树上引入了一个类似KMP中next数组的东西叫做Fail指针. 对于每一个节点,Fail指针指向该节点所代表的字符串中,次长的.在Trie树中存在的后缀(因为最长的在Trie树种存在的后缀就是其本身)所代表的节点. 举例:

算法模板——线段树1(区间加法+区间求和)

实现功能——1:区间加法:2:区间求和 最基础最经典的线段树模板.由于这里面操作无顺序之分,所以不需要向下pushup,直接累积即可 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end; 8 function min

算法模板——线段树5(区间开根+区间求和)

实现功能——1:区间开根:2:区间求和(此模板以BZOJ3038为例) 作为一个非常规的线段树操作,其tag也比较特殊呵呵哒 1 var 2 i,j,k,l,m,n:longint; 3 a,b:array[0..500000] of int64; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end; 8 function min(x,y:longint):long

【C++】最近公共祖先LCA(Tarjan离线算法)&amp;&amp; 洛谷P3379LCA模板

1.前言 首先我们介绍的算法是LCA问题中的离线算法-Tarjan算法,该算法采用DFS+并查集,再看此算法之前首先你得知道并查集(尽管我相信你如果知道这个的话肯定是知道并查集的),Tarjan算法的优点在于相对稳定,时间复杂度也比较居中,也很容易理解(个人认为). 2.思想 下面详细介绍一下Tarjan算法的思想: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5.寻找与当前点

【线段树】【P3372】模板-线段树

百度百科 Definition&Solution 线段树是一种log级别的树形结构,可以处理区间修改以及区间查询问题.期望情况下,复杂度为O(nlogn). 核心思想见百度百科,线段树即将每个线段分成左右两个线段做左右子树.一个线段没有子树,当且仅当线段表示的区间为[a,a]. 由于编号为k的节点的子节点为2k以及2k+1,线段树可以快速的递归左右叶节点. lazy标记:当进行区间修改的时候,如果一个区间整体全部被包含于要修改的区间,则可以将该区间的值修改后,将lazy标记打在区间上,不再递归左

CSU-ACM集训-模板-线段树进阶

A题 原CF 438D The Child and Sequence 题意 给一串数字,m次操作,1.区间查询:2.区间取模:3.单点修改 基本思路 考虑到模如果大于区间的最大值,则取模没有意义.若小于则向下查询并修改,考虑到一个数每次取模最多为原数的\(1/2\),则可认为修改次数不超过\(\log{2}{n}\) 时间复杂度为\(O(n\log{2}{n}\log{2}{n})\) #include<bits/stdc++.h> #define FOR(i,a,b) for(int i=a

模板 - 线段树

线段树还需要模板的菜鸡 #include<bits/stdc++.h> using namespace std; typedef long long ll; #define lt ls, l, m #define rt rs, m + 1, r #define ls (o<<1) #define rs (o<<1|1) const int MAXM = 100000 + 5; ll a[MAXM]; ll st[MAXM * 4], lazy[MAXM * 4]; in

算法模板——线段树4(区间加+区间乘+区间覆盖值+区间求和)

实现功能——1:区间加法 2:区间乘法 3:区间覆盖值 4:区间求和 这是个四种常见线段树功能的集合版哦...么么哒(其实只要协调好三种tag的关系并不算太难——前提是想明白了线段树的工作模式) 代码长度几经修改后也大为缩水 还有!!!——通过BZOJ1798反复的尝试,我的出来一个重要结论——尽量减少pushup操作的不必要使用次数,对于程序提速有明显的效果!!! 1 type vet=record 2 a0,a1:longint; 3 end; 4 var 5 i,j,k,l,m,n,a1,

算法模板——线段树7(骰子翻转问题)

实现功能:首先输入一个长度为N的序列,由1-4组成(1表示向前滚一下,2表示向后滚一下,3表示向左滚一下,4表示向右滚一下,骰子原始状态:上1前2左4右5后3下6),然后输入任意多个操作,输入“1 x y”表示将序列第x个数改成y,输入“2 x y”表示输出对于原始状态的骰子,按照从x到y的序列操作可以使骰子变成什么样子 原理:还是线段树,而且只需要点修改区间访问,不过这里面区间之间的合并不再是简单的累加了,而是——置换关系,通过置换关系的合并实现及时的维护即可 1 type 2 cube=ar