首页 > 其他分享 >Living-Dream 系列笔记 第77期

Living-Dream 系列笔记 第77期

时间:2024-09-11 21:36:54浏览次数:8  
标签:rt Living int tree mid 77 lt Dream lx

拖更了一个暑假。

P6492

很妙的线段树阿。

对于修改,我们无需用 lazy tag,只要每次跑到叶子节点去直接修改即可。

对于询问,答案即为树根的信息,因为它每次询问的都是整个区间。

最难的是 pushup 部分:

我们需要维护三个东西,ans,lx,rx,分别表示当前节点的 整个串的最长合法串 / 左端点开头的最长合法串 / 右端点开头的最长合法串;

ans 可以取自 左孩子的 ans / 右孩子的 ans / 左孩子的 rx \(+\) 右孩子的 lx(必须满足连接处的字符不一样)。

lx 可以取自 左孩子的 lx \(+\) 右孩子的 lx(要加上后面部分必须满足左孩子的 lx 是整个左孩子区间且连接处的字符不一样)。

rx 可以取自 右孩子的 rx \(+\) 左孩子的 lx(要加上后面部分必须满足右孩子的 rx 是整个右孩子区间且连接处的字符不一样)。

总结:本题维护了线段树上的多个信息,且涉及到了跨区间合并信息,十分具有启发性。

code
#include<bits/stdc++.h>
using namespace std;

const int N=1e6+5;
int n,q;
int a[N];
struct SGT{
	int ans,lx,rx;
}tree[N];

void pushup(int p,int lt,int rt){
	int mid=(lt+rt)>>1;
	
	tree[p].lx=tree[p*2].lx;
	if(tree[p*2].lx==mid-lt+1&&a[mid]!=a[mid+1])
		tree[p].lx+=tree[p*2+1].lx;
	
	tree[p].rx=tree[p*2+1].rx;
	if(tree[p*2+1].rx==rt-mid&&a[mid]!=a[mid+1])
		tree[p].rx+=tree[p*2].rx;
	
	tree[p].ans=max(tree[p*2].ans,tree[p*2+1].ans);
	if(a[mid]!=a[mid+1])
		tree[p].ans=max(tree[p].ans,tree[p*2].rx+tree[p*2+1].lx); 
}
void bld(int p,int lt,int rt){
	if(lt==rt){
		tree[p].ans=tree[p].lx=tree[p].rx=1;
		return;
	}
	int mid=(lt+rt)>>1;
	bld(p*2,lt,mid);
	bld(p*2+1,mid+1,rt);
	pushup(p,lt,rt);
}
void upd(int p,int lt,int rt,int x){
	if(lt>x||rt<x)
		return;
	else if(lt==x&&rt==x){
		a[x]^=1;
		return;
	}
	
	int mid=(lt+rt)>>1;
	upd(p*2,lt,mid,x);
	upd(p*2+1,mid+1,rt,x);
	pushup(p,lt,rt);
}

int main(){
	ios::sync_with_stdio(0);
	cin>>n>>q;
	bld(1,1,n);
	while(q--){
		int x;
		cin>>x;
		upd(1,1,n,x);
		cout<<tree[1].ans<<'\n';
	}
	return 0;
}

P2894

和上一题很相似。

这题有区间修改,所以要 lazy tag(注意有三种情形:无标记、空房、非空房)。

pushup 同上,只是要去掉「满足连接处的字符不一样」这个条件(有个问题,为什么不要判连接处的两个字符都为 \(0\)?第一判不了,因为这题是区间修改;第二因为 ans,lx,rx 会在打 lazy tag 时进行重置,因此无需担心正确性问题)。

询问的时候就找 左孩子 / 右孩子 / 中间拼接 这三个地方是否有一个地方的答案大于等于 \(x\),哪里满足就去哪里,一个都没有就无解。

总结:与上题类似,略。

code
#include<bits/stdc++.h>
using namespace std;

const int N=2e5+5;
int n,q;
int a[N],tag[N];
struct SGT{
	int ans,lx,rx;
}tree[N];

void addtag(int p,int lt,int rt,int val){
	tag[p]=val;
	if(val==1)
		tree[p].ans=tree[p].lx=tree[p].rx=0;
	else
		tree[p].ans=tree[p].lx=tree[p].rx=rt-lt+1;
}
void pushdown(int p,int lt,int rt){
	if(!tag[p])
		return;
	int mid=(lt+rt)>>1;
	addtag(p*2,lt,mid,tag[p]);
	addtag(p*2+1,mid+1,rt,tag[p]);
	tag[p]=0;
}
void pushup(int p,int lt,int rt){
	int mid=(lt+rt)>>1;
	tree[p].lx=tree[p*2].lx;
	if(tree[p*2].lx==mid-lt+1)
		tree[p].lx+=tree[p*2+1].lx;
	tree[p].rx=tree[p*2+1].rx;
	if(tree[p*2+1].rx==rt-mid)
		tree[p].rx+=tree[p*2].rx;
	tree[p].ans=max({tree[p*2].ans,tree[p*2+1].ans,tree[p*2].rx+tree[p*2+1].lx});
}
void bld(int p,int lt,int rt){
	if(lt==rt){
		tree[p].ans=tree[p].lx=tree[p].rx=1;
		return;
	}
	int mid=(lt+rt)>>1;
	bld(p*2,lt,mid);
	bld(p*2+1,mid+1,rt);
	pushup(p,lt,rt);
}
void upd(int p,int lt,int rt,int ql,int qr,int val){
	if(lt>qr||rt<ql)
		return;
	else if(ql<=lt&&rt<=qr){
		addtag(p,lt,rt,val);
		return;
	}
	pushdown(p,lt,rt);
	int mid=(lt+rt)>>1;
	upd(p*2,lt,mid,ql,qr,val);
	upd(p*2+1,mid+1,rt,ql,qr,val);
	pushup(p,lt,rt);
}
int qry(int p,int lt,int rt,int x){
	if(lt==rt)
		return lt;
	pushdown(p,lt,rt);
	int mid=(lt+rt)>>1;
	if(tree[p*2].ans>=x)
		return qry(p*2,lt,mid,x);
	if(tree[p*2].rx+tree[p*2+1].lx>=x)
		return mid-tree[p*2].rx+1;
	if(tree[p*2+1].ans>=x)
		return qry(p*2+1,mid+1,rt,x);
	return 0;
}

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>q;
	bld(1,1,n);
	while(q--){
		int op,x,y;
		cin>>op>>x;
		if(op==1){
			int pos=qry(1,1,n,x);
			if(pos!=0)
				upd(1,1,n,pos,pos+x-1,1);
			cout<<pos<<'\n';
		}
		else{
			cin>>y;
			upd(1,1,n,x,x+y-1,2);
		}
	}
	return 0;
}

CF620E

看到数颜色差点以为是莫队。。。

这题是维护子树信息,我们求出 dfs 序即可转化为序列问题。

然后它询问子树内节点的颜色种类数,我们考虑状压,将每个子树内的颜色情况压缩为一个二进制数(即有第 \(i\) 种颜色则第 \(i\) 为 \(1\),否则为 \(0\)),然后每个节点的状态即为两个子节点的状态或起来的值,每次询问时回答当前区间状态中 \(1\) 的个数即可。

总结:本题运用了 dfs 序将树上问题转化为序列问题、以及二进制压缩的技巧,尤其是后者十分精妙,需要牢记,可以在数颜色这一类的题目中使用。

标签:rt,Living,int,tree,mid,77,lt,Dream,lx
From: https://www.cnblogs.com/XOF-0-0/p/18409035

相关文章

  • LeetCode 977.有序数组的平方 (java)
    给你一个按非递减顺序排序的整数数组nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。示例1:输入:nums=[-4,-1,0,3,10]输出:[0,1,9,16,100]解释:平方后,数组变为[16,1,0,9,100],排序后,数组变为[0,1,9,16,100]示例2:输入:nums=[-7,-3,2,3,11]输出:[4,9,9,......
  • 洛谷题单指南-分治与倍增-P1177 【模板】归并排序
    原题链接:https://www.luogu.com.cn/problem/P1177题意解读:归并排序模版题。解题思路:第一步:确定分界点。mid=(l+r)/2第二步:排序。对左右两边递归排序第三步:归并。合并左右两边排序好的内容关键在第三步:通过双指针对两个有序数组进行合并100分代码:#include<bits/std......
  • Windows远程桌面授权远程代码执行漏洞CVE-2024-38077(POC、EXP)
    目录漏洞描述关键信息漏洞影响漏洞危害等级影响范围漏洞解决方案临时缓解方案升级修复方案POCEXP使用参考漏洞描述CVE-2024-38077是Windows远程桌面授权服务(RDL)中的一个堆溢出漏洞。该漏洞在解码用户输入的许可密钥包时,未正确验证解码后的数据长度与缓冲区......
  • P1775 石子合并(弱化版)
    P1775石子合并(弱化版)感觉dp太难了,这真的感觉太难学了,但是还要写题记积累啊,唉!感觉不用讲题意了(那你也别讲题解了)就是石子之间可以合并,合并的代价是这堆石子数,问如何合并全部石子后总代价最小。考虑用区间dp,设状态为\(dp[i][j]\)为区间\([i,j]\)的最小代价,转移时先枚举区......
  • 【连续多年EI检索,去年EI检索只需2.5个月!学生易中稿,性价比超高!SPIE出版 (ISSN号: 0277-
    由重庆理工大学、重庆市特种设备检测研究院和重庆市电子学会联合主办,重庆邮电大学、韩国仁荷大学、重庆工程学院、重庆能源职业学院协办,光纤传感与光电检测重庆市重点实验室、现代光电检技术与仪器重庆市高校重点实验室、西部复杂环境机电设备安全国家市场监管重点实验室、智能......
  • 如何通过组合手段大批量探测CVE-2024-38077
    背景近期正值多事之秋,hvv中有CVE-2024-38077专项漏洞演习,上级police也需要检查辖区内存在漏洞的资产,自己单位领导也收到了情报,在三方共振下这个大活儿落到了我的头上。WindowsServerRDL的这个漏洞原理就不过多介绍,本文重点关注如何满足大批量探测的需求。问题CVE-2024-38077......
  • 创新体验来袭,智象未来(HiDream.ai)开启电商多模态交互新时代
    立足人工智能技术的前沿领域,智象未来(HiDream.ai)不断深化其多模态生成式技术的研发,引领着全球创新的潮流。公司成功构建了视觉多模态基础模型及其应用,为交互式智能内容创作设立了全新的行业标杆。智象未来(HiDream.ai)独立开发的“秩象大模型”具备跨文本、图像、视频、3D等多种模......
  • 计算机毕业设计必看必学!! 11779 猪场管理系统的设计与实现,原创定制程序, java、PHP、
    摘要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对猪场管理系统等问题,对猪场管理系统进行研究分析,然后开发设计出猪场管理系统以解决问题。猪......
  • RL6577/RTS5765DL量产工具,RTS5765DL+B47R扩容开卡修复,金士顿NV2 2TB假固态硬盘抢救记
    之前因为很长时间不买固态硬盘,没注意到NVME的固态盘也有了假货和扩容盘,花200多块买了个2TB的金士顿NV2固态硬盘,我原本以为NV1的假货最多是用黑片冒充正片,结果没想到NV2居然有扩容的。后来发现是扩容盘的时候,已经过了自动收货期限了。最后只能尝试重新开卡,尽量降低损失。首先......
  • 金士顿NV2 2TB假固态硬盘抢救记,RL6577/RTS5765DL量产工具,RTS5765DL+B47R扩容开卡修复
    之前因为很长时间不买固态硬盘,没注意到NVME的固态盘也有了假货和扩容盘,花200多块买了个2TB的金士顿NV2固态硬盘,我原本以为NV1的假货最多是用黑片冒充正片,结果没想到NV2居然有扩容的。后来发现是扩容盘的时候,已经过了自动收货期限了。最后只能尝试重新开卡,尽量降低损失。首先......