首页 > 其他分享 >线段树进阶

线段树进阶

时间:2024-02-16 09:00:49浏览次数:36  
标签:cnt struct int 线段 tree 扫描线 进阶

线段树进阶

线段树分治

P5787

判断二分图可以用扩展域并查集,采用线段树分治,线段树上的每一个结点作为每一段时间。

每个结点上的修改和回溯需要用到可撤销的并查集。

时间复杂度 \(O(n\log k \log n)\)

扫描线

扫描线求矩形面积

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
int x[N];
struct node1{
	int xa,xb,y,type;
}line[N];
struct node2{
	int l,r;
	ll sum;
	int cnt;
}tree[N<<3];
bool cmp1(int x,int y){
	return x < y;
}
bool cmp2(node1 x,node1 y){
	return x.y < y.y;
}
void build(int p,int l,int r){
	tree[p].l = x[l];
	tree[p].r = x[r];
	if(r-l<=1){
		return;
	}
	int mid = (l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid,r);
}
void update(int p){
	if(tree[p].cnt){
		tree[p].sum = tree[p].r - tree[p].l;
	}else{
		tree[p].sum = tree[p<<1].sum + tree[p<<1|1].sum;
	}
}
void add(int p,int l,int r,int c){
	if(l <= tree[p].l && r >= tree[p].r){
		tree[p].cnt += c;
		update(p);
		return;
	}
	if(l < tree[p<<1].r){
		add(p<<1,l,r,c);
	}
	if(r > tree[p<<1|1].l){
		add(p<<1|1,l,r,c);
	}
	update(p);
}
int main(){
	int n;
	ll ans = 0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int xa,xb,ya,yb;
		scanf("%d%d%d%d",&xa,&ya,&xb,&yb);
		x[i] = xa;
		x[i+n] = xb;
		line[i] = (node1){xa,xb,ya,1};
		line[i+n] = (node1){xa,xb,yb,-1};
	}
	n <<= 1;
	sort(x+1,x+1+n,cmp1);
	sort(line+1,line+1+n,cmp2);
	build(1,1,n);
	for(int i=1;i<=n;i++){
		ans += tree[1].sum * (line[i].y - line[i-1].y);
		add(1,line[i].xa,line[i].xb,line[i].type);
	}
	printf("%lld",ans);
} 

扫描线求矩形周长

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int x[N];
struct node1{
	int xa,xb,y,type;
}line[N];
struct node2{
	int l,r,sum,cnt;
	int t;
	bool lc,rc;
}tree[N<<3];
bool cmp1(int x,int y){
	return x < y;
}
bool cmp2(node1 x,node1 y){
	return x.y == y.y ? x.type > y.type : x.y < y.y;
}
void build(int p,int l,int r){
	tree[p].l = x[l];
	tree[p].r = x[r];
	if(r-l<=1){
		return;
	}
	int mid = (l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid,r);
}
void update(int p){
	if(tree[p].cnt){
		tree[p].sum = tree[p].r - tree[p].l;
		tree[p].lc = true;
		tree[p].rc = true;
		tree[p].t = 2;
	}else{
		tree[p].lc = tree[p<<1].lc;
		tree[p].rc = tree[p<<1|1].rc;
		tree[p].t = tree[p<<1].t + tree[p<<1|1].t;
		tree[p].sum = tree[p<<1].sum + tree[p<<1|1].sum;
		if(tree[p<<1].rc && tree[p<<1|1].lc){
			tree[p].t -= 2;
		}
	}
}
void add(int p,int l,int r,int c){
	if(l <= tree[p].l && r >= tree[p].r){
		tree[p].cnt += c;
		update(p);
		return;
	}
	if(l < tree[p<<1].r){
		add(p<<1,l,r,c);
	}
	if(r > tree[p<<1|1].l){
		add(p<<1|1,l,r,c);
	}
	update(p);
}
int main(){
	int n,ans = 0,last = 0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int xa,xb,ya,yb;
		scanf("%d%d%d%d",&xa,&ya,&xb,&yb);
		x[i] = xa;
		x[i+n] = xb;
		line[i] = (node1){xa,xb,ya,1};
		line[i+n] = (node1){xa,xb,yb,-1};
	}
	n <<= 1;
	sort(x+1,x+1+n,cmp1);
	sort(line+1,line+1+n,cmp2);
	build(1,1,n);
	for(int i=1;i<=n;i++){
		add(1,line[i].xa,line[i].xb,line[i].type);
		ans += abs(last-tree[1].sum);
		last = tree[1].sum;
		ans += tree[1].t*(line[i+1].y - line[i].y);
	}
	printf("%d",ans);
} 

线段树合并

线段树分裂

标签:cnt,struct,int,线段,tree,扫描线,进阶
From: https://www.cnblogs.com/WhileTrueRP/p/18016899/xian_duan_shu_jin_jie

相关文章

  • 大数进阶(1)——反射(Π1)
    一点吐槽序数分析(OrdinalAnalysis)这一脉实际上是从证明论衍生出来的,因此去找文献通常会找到各种证明某一公理系统强度的文献,并没有系统的综述踏入序数之后,几乎没有统一记号,需要在各人的记号中切换,加之数理逻辑本身就需要一堆新记号,可谓是乱七八糟,有一种踏入前沿的美(确实即使从G......
  • 线段树
    【前置知识】运算律,单位元。运算律基本就是交换律、结合律、分配律。单位元:假设我们现在有一个运算\(\bigoplus\)。如果\(a\bigoplusb=b\bigoplusa=a\),称\(b\)是运算\(\bigoplus\)的单位元。【线段树】线段树是一个树形数据结构。满二叉树;倍增的思想,分治的手......
  • 李超线段树
    李超线段树线段树的扩展版本用来动态维护平面上直线支持插入直线/线段,查询横坐标某处覆盖的线中纵坐标最大/最小值可以用于斜率优化DP插入直线这里直线是线段树上维护的信息,表示当前区间中点处最优的直线同时相当于区间修改,直线也是标记,这个区间内都可能有这条直线但是标......
  • 2024.2.14 WC24 线段树 / CF1572D / lgP3679
    西安Day1。感冒还没好,牙龈炎也没好,明天还要考试,又要坐牢了/kk。今天是tyy的图论选讲,感觉前面网络流部分还是在线的,平面图部分毒瘤tyy拿出了他的员交课件,恐怖,直接下线了。看了NAVI和Faze的预选赛,你们俩怎么都打的这么稀碎/fn。Override真好听。「WC2024」线段树我......
  • 字符串进阶题目选做
    字符串进阶一些不那么裸的字符串题,甚至出现了parent树优化建图这种离谱的东西。前置知识:kmp,字符串哈希,AC自动机,SA,SAM,ManacherCF914FSubstringsinaString题意:给定字符串,要求支持单点修改,询问时给出字符串,求在\([l,r]\)中出现多少次。思路:考虑一般的字符串维护方法都......
  • 线段树分治学习笔记
    线段树分治线段树分治是一种可以离线处理带撤销问题的常用手段。一般而言,题目中加入操作很好维护,但删除操作不好维护,这时可以对时间维建线段树,把每一个操作加入其存在时间段对应的线段树节点上,然后处理所有询问,进入一个节点时将这个节点里的操作加入,递归左右儿子,然后撤销这一次做......
  • 线段树进阶奇淫巧计
    看本文文字部分可以少带脑子,但是代码部分仔细看了因为不一定编译了不一定对动态开点一般来说线段树的空间开销是比较巨大的,需要\(4n\)的空间,一般其实是可以支撑的,但是权值线段树就不一定了。值域级别的代价是支持不了的。一般在动态开点的前提下只需要支持单点操作一旦是序......
  • 线段树
    3.区间操作与Lazy-Tag本节介绍线段树的核心操作Lazy-Tag,并给出区间修改\(+\)区间查询的模板。在线段树上,如果直接进行区间修改,时间复杂度为\(\mathcal{O}(N\logN)\)。而Lazy-Tag可以将其降为\(\mathcal{O}(\logN)\)。Lazy-Tag方法用\(lz_p\)统一记录区间\(p......
  • 线段树维护字符串哈希
    [ABC331F]PalindromeQuery#include<bits/stdc++.h>usingnamespacestd;#defineendl"\n"#defineintlonglongtypedeflonglongll;constintbase=131;constintp1=1222827239;constintN=1e6+100;intn,q,pn[N];strings......
  • 最新Burp Suite进阶技术
    Burp Suite进阶1.Burp ScannerBurpScanner主要用于自动检测Web系统的各种漏洞。本节介绍BurpScanner的基本使用方法,在实际使用中可能会有所改变,但大体环节如下。首先,确认BurpSuite正常启动并完成浏览器代理的配置。然后进入BurpProxy,关闭代理拦截功能,快速浏览需要扫描的域......