首页 > 其他分享 >洛谷P5494 【模板】线段树分裂

洛谷P5494 【模板】线段树分裂

时间:2023-04-18 12:01:15浏览次数:50  
标签:cnt 洛谷 int P5494 tr mid return root 模板

传送门

  需要的前置知识:线段树合并。

  感觉会了线段树合并这个就很简单,线段树分裂就是在把一颗权值线段树值域在[x, y]的区间分裂出来单独成一个线段树,那么我们只需要从新树q和旧树p的根节点一起走,如果走到当前p被[x, y]完全包含的路径就把p的编号给q,并且把p改为0就行了,注意这里p和q要传引用,并且不能直接拿q = p这样p和q的地址会一样,所以一改开一个int类型tmp = p,q = tmp,p = 0然后我们return即可,然后注意这题卡空间需要废点优化,我们把线段树合并不需要的那一部分点存进stk数组,并且将这个结点的tr清空即可。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <map>
#include <deque>
#include <vector>

typedef long long ll;
typedef std::pair<int, int> PII;
#define ls tr[u].l
#define rs tr[u].r

const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10, M = 2e5 + 10;

int n, m;

int root[N], cnt, a[N];
int stk[N << 5], top;

struct node {
	int l, r;
	ll cnt;
}tr[N << 5];

inline int get() {
	if(!top) {
		return ++ cnt;
	} 

	int p = stk[top --];
	tr[p] = {0, 0, 0};
	
	return p;
}

inline void pushup(int u) {
	tr[u].cnt = tr[tr[u].l].cnt + tr[tr[u].r].cnt;
}

inline void build(int &u, int L, int R) {
	u = get();
	if(L == R) {
	
		tr[u].cnt = a[L];
		return ;
	} 
	
	int mid = L + R >> 1;
	build(tr[u].l, L, mid);
	build(tr[u].r, mid + 1, R);
	
	pushup(u);
}

inline void split(int &p, int &q, int L, int R, int x, int y) {
	if(!q) q = get();
	if(L >= x && R <= y) {
		q = p;
		p = 0;
		return ;
	}
	
	int mid = L + R >> 1;
	if(x <= mid)	split(tr[p].l, tr[q].l, L, mid, x, y);
	if(y > mid)	split(tr[p].r, tr[q].r, mid + 1, R, x, y);
	
	pushup(p);
	pushup(q);
}

inline int merge(int p, int q, int L, int R){
	if(!p)	return q;
	if(!q)	return p;
	stk[++ top] = q;
	if(L == R){
		tr[p].cnt += tr[q].cnt;
		return p;
	}	
	int mid = L + R >> 1;
	tr[p].l = merge(tr[p].l, tr[q].l, L, mid);
	tr[p].r = merge(tr[p].r, tr[q].r, mid + 1, R);

	pushup(p);
	return p;
}

inline void insert(int &p, int L, int R, ll x, int v) {
	if(!p) p = get();
	if(L == R) {
		tr[p].cnt += x;
		return ;
	}
	
	int mid = L + R >> 1;
	if(v <= mid)	insert(tr[p].l, L, mid, x, v);
	else insert(tr[p].r, mid + 1, R, x, v);
	
	pushup(p);
}

inline ll query(int p, int L, int R, int x, int y) {
	if(!p)	return 0;

	if(L >= x && R <= y)	return tr[p].cnt;
	
	int mid = L + R >> 1;
	ll res = 0;
	
	if(x <= mid)	res += query(tr[p].l, L, mid, x, y);
	if(y > mid) res += query(tr[p].r, mid + 1, R, x, y);
	
	return res;
}

inline int queryk(int p, int L, int R, ll k) {
	if(L == R)	return L;
	int mid = L + R >> 1;
	if(tr[tr[p].l].cnt < k) 	return queryk(tr[p].r, mid + 1, R, k - tr[tr[p].l].cnt);
	return queryk(tr[p].l, L, mid, k);
}

inline void solve() {
	std::cin >> n >> m;

	for (int i = 1; i <= n; i ++)	std::cin >> a[i];
	build(root[1], 1, n);
	
	int timestap = 1;
	for (int i = 1; i <= m; i ++) {
		int op;
		std::cin >> op;
		if (!op) {
			int p, x, y;
			std::cin >> p >> x >> y;
			split(root[p], root[++ timestap], 1, n, x, y);
	
		} else if (op == 1) {
			int p, q;
			std::cin >> p >> q;
			merge(root[p], root[q], 1, n);
			
			tr[root[i]].cnt << '\n';
		} else if (op == 2) {
			int p, v;
			ll x;
			std::cin >> p >> x >> v;
			insert(root[p], 1, n, x, v);

		} else if (op == 3) {
			int p, x, y;
			std::cin >> p >> x >> y;
			std::cout << query(root[p], 1, n, x, y) << '\n';
		} else {
			 int p;
			 ll k;
			 std::cin >> p >> k;
			 
			 if(tr[root[p]].cnt < k)	std::cout << "-1" << '\n';
			 else std::cout << queryk(root[p], 1, n, k) << '\n';
		}
	}
}

int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    
   //freopen("D:\\in.txt","r",stdin); //输入重定向,输入数据将从D盘根目录下的in.txt文件中读取 
    int _ = 1;
    //std::cin >> _;
    while(_ --)
    	solve();

    return 0;
}
		

标签:cnt,洛谷,int,P5494,tr,mid,return,root,模板
From: https://www.cnblogs.com/qdhys/p/17329078.html

相关文章

  • Python Django 模板的使用
    新建templates/header.html文件<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>header</title></head><body><h1>东营职业学院</h1><p>......
  • 洛谷 p1102 A-B数对
    题目背景出题是一件痛苦的事情!相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的A+BProblem,改用A-B了哈哈!题目描述给出一串正整数数列以及一个正整数 C,要求计算出所有满足A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。输入格式输入共两行。......
  • html模板里的表达式不能用小于号
    今天用angular写*ngIf="item.cnt <= 5"这个表达式的时候报错,他将<后面的东西当做html标签来看了,怎么办呢可以用html转义字符来表示小于号<换成下面就可以了*ngIf="item.stockCnt &lt= 5"<<&#60;小于号>>&#62;大于号......
  • jQuery Templates模板插件
    jQuery团队提供了一个模板插件,但非常可惜的是jquery团队放弃对其维护,我们对其方法和语法进行简单简绍源码官方的网址:http://api.jquery.com/category/plugins/templates文档的网址:http://api.jquery.com/category/plugins/templates使用该插件必须先引入对应js //依赖jquery<sc......
  • C#模拟C++模板特化对类型的值的支持
    概述C++的模板相比于C#的泛型,有很多地方都更加的灵活(虽然代价是降低了编译速度),比如C++支持变长参数模板、支持枚举、int等类型的值作为模板参数。C++支持枚举、int等类型的值作为模板参数,为C++的静态多态编程提供了很好的帮助,比如根据枚举值编译期确定某个对象的行为策略等(下文......
  • leaflet.openPopup() 方法传入参数是个模板字符串,如何将其改为使用vue的模板实现,可以
    注:这个问题是我使用cursor得到的回答。问:leaflet.openPopup()方法传入参数是个模板字符串,如何将其改为使用vue的模板实现,可以支持数据双向绑定为了将 this.map.openPopup() 方法中的字符串模板替换为支持双向数据绑定的 Vue 模板,您可以使用 Vue.extend() 方法创建一个新......
  • 洛谷P7492 [传智杯 #3 决赛] 序列 题解 数列分块
    题目链接:https://www.luogu.com.cn/problem/P7492解题思路:分块。解题思路全部来自yzy1大佬的博客额外掌握技能:编译时加入-Wall参数。示例程序:#include<bits/stdc++.h>usingnamespacestd;constintmaxn=1e5+5;intn,m,blo,//n表示数列长度,m表......
  • Helm模板.Files.Get函数
     常规用法apiVersion:v1kind:ConfigMapmetadata:name:templatesbinaryData:file1:{{.Files.Get"files/file1"|b64enc}}file2:{{.Files.Get"files/file2"|b64enc}}#错误示例apiVersion:v1kind:ConfigMapmetadata:name:temp......
  • vue table 里面 slot 的模板复用 slot-scope template v-for
    vuetable里面slot的模板复用slot-scopetemplatev-for需求经常在table里面要有自定义列,但是会有相同的自定义列,这个时候又不想写很多一样的template,就可以用这种方式代码<template:slot="slotName"v-for="slotNamein['slotName1','slotName2','slot......
  • c++笔记——类模板
    类模板的几个简单测试例程几个要点:(1)类模板类型,在实例化时需要显式类型名称(2)已经显式类型后,传入的参数如果不是相应类型,则会发生强制转换(3)在类外定义的成员函数,需要加上模板参数列表和类作用域,且类作用域带类型列表(4)多个参数模板时,可以在函数中使用其中若干个,不用全部都使用。......