首页 > 其他分享 >permu题解(树上莫队)(非正解)

permu题解(树上莫队)(非正解)

时间:2023-06-11 10:22:46浏览次数:43  
标签:mmax int 题解 非正解 rmax lmax root rid 莫队

题目传送门

题意

给出一个长度为$n$的排列$P(P1,P2,...Pn)$,以及$m$个询问。每次询问某个区间$[l,r]$中,最长的值域 连续段长度。

思路

首先这道题事求连续段的长度,打个莫队先

#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Testify{	
	inline int read(){
		int f(1),x(0);
		char ch=getchar();
		for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
		for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
		return f*x;
	}
	inline void Write(int x){
		if(x<0) putchar('-'),x=-x;
		if(x>9) Write(x/10);
		putchar(x%10+'0');
		return ;
	}
	inline void write(int x){
		Write(x);
		putchar('\n');
		return ;
	}
}
using namespace Testify;
const int N=5e4+5;
int n,m,blo,col[N],pos[N];

struct sb{
	int l,r,k;
	friend inline bool operator<(const sb&a,const sb&b){
		if(pos[a.l]!=pos[b.l]){
			return pos[a.l]<pos[b.l];
		}
		if(pos[a.l]&1) return pos[a.r]>pos[b.r];//奇偶性优化
		return pos[a.r]<pos[b.r];
	}
	
}q[N];

main(){
	n=read(),m=read();
	blo=sqrt(n);
	for(register int i=1;i<=n;i++){
		col[i]=read();
		pos[i]=(i-1)/t+1;
	}
	for(register int i=1;i<=m;i++){
		q[i].l=read(),q[i].r=read(),q[i].k=i;
	}
	int l=1,r=0;
	
	
	return 0;
}

然后考虑用线段树求最长连读段长度

struct node{
	int len,lmax,rmax,mmax;
    
}t[N<<2];

pushup操作

inline void pushup(int root){
	t[root].lmax=t[lid].lmax;
	t[root].rmax=t[rid].rmax;
	if(t[lid].lmax==t[lid].len) {
		t[root].lmax+=t[rid].lmax;
	}
	if(t[rid].rmax==t[rid].len){
		t[root].rmax+=t[lid].rmax;
	}
	t[root].mmax=max({t[lid].mmax,t[rid].mmax,t[lid].rmax+t[rid].lmax});
	return;
}

求解$ls$,那么我们有两个选择,选择左边区间的$ls$,或者是把左边区间全部选了然后再选取右边区间的$ls$。因为子段必须保持连续性,所以这两个选择是最优的。

同样道理求解$rs$,那么我们有两个选择,选择右边区间的$rs$,或者是把右边区间全部选了然后再选取左边区间的$rs$。因为子段必须保持连续性,所以这两个选择是最优的。

求解$ms$,那么我们有两个选择,选择右边区间的$ms$,或者是左边区间的$ ms$,或者是左边区间的$rs$和右边区间的$ls$的和,因为选择保证了连续子段的连续性,所以最优解一定在上面三种选择中。

建树

inline void build(int root,int l,int r){
	t[root].len=r-l+1;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(lid,l,mid);
	build(rid,mid+1,r);
}

这样写不用pushup2更新len捏

插入和删除(莫队操作)

inline void insert(int root,int l,int r,int x){
	if(l==r){
		t[root].lmax=1;
		t[root].mmax=1;
		t[root].rmax=1;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) insert(lid,l,mid,x);
	else insert(rid,mid+1,r,x);
	pushup(root);
}
inline void dele(int root,int l,int r,int x){
	if(l==r){
		t[root].lmax=0;
		t[root].mmax=0;
		t[root].rmax=0;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) dele(lid,l,mid,x);
	else dele(rid,mid+1,r,x);
	pushup(root);
}

莫队移动找答案

int l=1,r=0;
	for(register int i=1;i<=m;i++){
		//注意这里要先insert再dele否则会TLE(?  
		while(l>q[i].l) insert(1,1,n,col[--l]);
		while(r<q[i].r) insert(1,1,n,col[++r]);
     		while(l<q[i].l) dele(1,1,n,col[l++]);
		while(r>q[i].r) dele(1,1,n,col[r--]);
		ans[q[i].k]=t[1].mmax;
	}

或者这样写

	for(register int i=l;i<=r;i++){
		insert(1,1,n,col[i]);
	}
	for(register int i=1;i<=m;i++){
		while(l>q[i].l) insert(1,1,n,col[--l]);
		while(r<q[i].r) insert(1,1,n,col[++r]);
		while(l<q[i].l) dele(1,1,n,col[l++]);
		while(r>q[i].r) dele(1,1,n,col[r--]);
		ans[q[i].k]=t[1].mmax;
	}

输出

for(register int i=1;i<=m;i++){
		write(ans[i]);
	}

完结撒出生

标签:mmax,int,题解,非正解,rmax,lmax,root,rid,莫队
From: https://www.cnblogs.com/phigros/p/17472558.html

相关文章

  • mysql运行sql文件时,timestamp默认值出错问题解决
    出现了---Invaliddefaultvaluefor'reward_time' 直接打开sql文件,将字段reward_time类型值替换成NULL即可 ......
  • 和与积 题解 简单二分查找
    题目大意:给定两个整数\(a(2\lea\le2\times10^9)\)和\(b(1\leb\le10^{18})\)。判断是否存在两个正整数\(x\)和\(y\),同时满足如下两个条件:\(x+y=a\)\(x\timesy=b\)解题思路:用\(a-x\)表示\(y\),可以得到面积的表达式为\(x\times(a-x)\),然后......
  • 佳佳的 Fibonacci 题解
    佳佳的Fibonacci题解题目:题解:数据范围很大,暴力超时,考虑的是矩阵优化递推,关键是求出递推矩阵,然后结合矩阵快速幂求解如何求解递推矩阵?我们首先知道斐波那契的递推式:f[i]=f[i-1]+f[i-2]——>①然后题目中给我们了T(n)的递推式:T(n)=F[1]+2F[2]+3F[3]+...+nF[n]——>②考......
  • 题解 NOD2207C【不降序列】
    problem给出n个数组A1​到An​,数组中的元素为1到M之间的数字。数组之间也存在字典序,即从第一个数开始逐位比较,一旦某个数字大于另一个,则数组的字典序大于另一个,如果某一个是另一个的前缀,则前缀的字典序更小。你可以选择一些大于0的数字执行减法操作,一旦选中某个数......
  • 题解 NOD2207D【电报】
    前置知识:高斯消元已知\(n\)元线性一次方程组。关于\(x_1,x_2,\cdots,x_n\)。\[\begin{cases}a_{1,1}x_1+a_{1,2}x_2+\cdots+a_{1,n}x_n=b_1\\a_{2,1}x_1+a_{2,2}x_2+\cdots+a_{2,n}x_n=b_2\\\cdots\\a_{n,1}x_1+a_{n,2}x_2+\cdots......
  • [SHOI2011]双倍回文 题解
    [SHOI2011]双倍回文题解看了一些写回文自动机的大佬的代码,我深感敬畏,于是我转身向Manacher走去现在荣登最优解第一页……说实话,这个方法的复杂度是很玄学的,但是加了一些优化之后,就几乎不可能被卡到\(O(n^2)\)了。具体思路如下:预处理字符串部分就略过吧我们预先跑一......
  • P7959 [COCI2014-2015#6] WTF 题解
    P7959[COCI2014-2015#6]WTF题解呃,是一道DP题说实话,原题实际上是不要输出一种方法的……但是似乎放这道题的人想增加一点难度?这里有两种做法,但都是DP。预备观察我们首先观察一些性质,以方便解题。循环不变:我们可以观察到,在\(n\)次变换后,序列会还原。也就是说,两个......
  • 题解 BZOJ4399 魔法少女LJJ
    前言XXX:你瞅你长得那个B样,俺老孙就(氧化钙)......这魔法(J8)少女能不能去死啊啊啊啊啊啊啊啊啊啊......正文"LJJ你是来搞笑的吧"你说得对,但是这数据就是骗人的.首先看题面:然后看样例:最后看数据范围:我惊奇的发现\(c\le7\)!家人们我真难绷qaq...问题分析显......
  • [AGC055B] ABC Supremacy 题解
    [AGC055B]ABCSupremacy题解题目描述给定两个长度为 \(n\) 的字符串 \(a\),\(b\)。你可以进行若干次以下操作:若 \(a\) 中的一个子串为 ABC,BCA 或 CAB,那么可以将这个子串替换为 ABC,BCA 或 CAB。求能否将 \(a\) 变成 \(b\),输出 YES 或 NO。解析不难发现,......
  • chrome 跨域问题解决
    1.后端设置了跨域,https下可以,http不可以高版本chrome配置了策略,如果访问私有网络,会出现禁止跨域chrome://flags/#block-insecure-private-network-requestsBlockinsecureprivatenetworkrequests.......