【BZOJ4358】permu kd-tree

【BZOJ4358】permu

Description

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

Input

第一行两个整数n,m。

接下来一行n个整数,描述P。

接下来m行,每行两个整数l,r,描述一组询问。

Output

对于每组询问,输出一行一个整数,描述答案。

Sample Input

8 3
3 1 7 2 5 8 6 4
1 4
5 8
1 7

Sample Output

3
3
4

HINT

对于询问[1,4],P2,P4,P1组成最长的值域连续段[1,3];

对于询问[5,8],P8,P5,P7组成最长的值域连续段[4,6];

对于询问[1,7],P5,P7,P3,P6组成最长的值域连续段[5,8]。

1<=n,m<=50000

题解:一开始想莫队没想出来,然后就去膜拜了Claris的题解

然后下传标记的时候又有些不明白,于是又去膜拜了Claris的代码。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=50010;
const int inf=1<<30;
int n,m,X,rt,D;
int p[maxn],v[maxn],ans[maxn];
struct kd
{
	int v[2],sm[2],sn[2],ls,rs,ts,val,tt,org,ht,hs,hv;
	kd () {}
	kd (int a,int b){v[0]=sm[0]=sn[0]=a,v[1]=sm[1]=sn[1]=b,ls=rs=ts=val=hs=hv=0,tt=ht=-inf;}
}t[maxn];
bool cmp(const kd &a,const kd &b)
{
	return (a.v[D]==b.v[D])?(a.v[D^1]<b.v[D^1]):(a.v[D]<b.v[D]);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void ps(int x,int y)
{
	t[x].val+=y;
	if(t[x].val>t[x].hv)	t[x].hv=t[x].val;
	if(t[x].tt>=0)
	{
		t[x].tt+=y;
		if(t[x].tt>t[x].ht)	t[x].ht=t[x].tt;
	}
	else
	{
		t[x].ts+=y;
		if(t[x].ts>t[x].hs)	t[x].hs=t[x].ts;
	}
}
void pt(int x,int y)
{
	t[x].val=y;
	if(t[x].val>t[x].hv)	t[x].hv=t[x].val;
	t[x].tt=y,t[x].ts=0;
	if(t[x].tt>t[x].ht)	t[x].ht=t[x].tt;
}
void phs(int x,int y)
{
	t[x].hv=max(t[x].hv,t[x].val+y);
	if(t[x].ht>=0)	t[x].ht=max(t[x].ht,t[x].tt+y);
	else	t[x].hs=max(t[x].hs,t[x].ts+y);
}
void pht(int x,int y)
{
	t[x].hv=max(t[x].hv,y);
	t[x].ht=max(t[x].ht,y);
}
void pushup(int x,int y)
{
	t[x].sm[0]=max(t[x].sm[0],t[y].sm[0]);
	t[x].sm[1]=max(t[x].sm[1],t[y].sm[1]);
	t[x].sn[0]=min(t[x].sn[0],t[y].sn[0]);
	t[x].sn[1]=min(t[x].sn[1],t[y].sn[1]);
}
void pushdown(int x)
{
	if(t[x].hs)
	{
		if(t[x].ls)	phs(t[x].ls,t[x].hs);
		if(t[x].rs)	phs(t[x].rs,t[x].hs);
		t[x].hs=0;
	}
	if(t[x].ht>=0)
	{
		if(t[x].ls)	pht(t[x].ls,t[x].ht);
		if(t[x].rs)	pht(t[x].rs,t[x].ht);
		t[x].ht=-inf;
	}
	if(t[x].ts)
	{
		if(t[x].ls)	ps(t[x].ls,t[x].ts);
		if(t[x].rs)	ps(t[x].rs,t[x].ts);
		t[x].ts=0;
	}
	if(t[x].tt>=0)
	{
		if(t[x].ls)	pt(t[x].ls,t[x].tt);
		if(t[x].rs)	pt(t[x].rs,t[x].tt);
		t[x].tt=-inf;
	}
}
int build(int l,int r,int d)
{
	if(l>r)	return 0;
	int mid=(l+r)>>1;
	D=d,nth_element(t+l,t+mid,t+r+1,cmp);
	t[mid].ls=build(l,mid-1,d^1),t[mid].rs=build(mid+1,r,d^1);
	if(t[mid].ls)	pushup(mid,t[mid].ls);
	if(t[mid].rs)	pushup(mid,t[mid].rs);
	return mid;
}
void updata(int x)
{
	if(!x)	return;
	if(t[x].sn[0]>X||t[x].sm[1]<X)
	{
		pt(x,0);
		return ;
	}
	if(t[x].sm[0]<=X&&t[x].sn[1]>=X)
	{
		ps(x,1);
		return ;
	}
	pushdown(x);
	if(t[x].v[0]<=X&&t[x].v[1]>=X)	t[x].val++,t[x].hv=max(t[x].hv,t[x].val);
	else	t[x].val=0;
	updata(t[x].ls),updata(t[x].rs);
}
void dfs(int x)
{
	if(!x)	return ;
	pushdown(x),ans[t[x].org]=t[x].hv;
	dfs(t[x].ls),dfs(t[x].rs);
}
int main()
{
	n=rd(),m=rd();
	int i,a,b;
	for(i=1;i<=n;i++)	p[rd()]=i;
	for(i=1;i<=m;i++)	a=rd(),b=rd(),t[i]=kd(a,b),t[i].org=i;
	rt=build(1,m,0);
	for(i=1;i<=n;i++)
		X=p[i],updata(rt);
	dfs(rt);
	for(i=1;i<=m;i++)	printf("%d\n",ans[i]);
	return 0;
}
时间: 2024-12-28 23:41:25

【BZOJ4358】permu kd-tree的相关文章

【bzoj4358】permu【XSY1535】seq(莫队+并查集)

考虑莫队,但是我们发现这个东东只支持\(ins\)(至于怎么支持等会再讲),不支持\(del\)操作,所以我们构造一种只\(ins\)不\(del\)的莫队. 由于我们按莫队的方法排序,第一关键字为\(l\)所在的块,第二关键字为\(r\).所以当排完序后,肯定是当\(l\)所在的块相同时,\(r\)单调递增,所以我们对\(l\)所在的块相同的询问进行处理.设对于块\(B\),它的末尾位置为\(end\),我们先找出在排完序中的数组中所有\(l\)所在的块为\(B\)的询问\(q_1\).\(q

AC日记——【模板】Link Cut Tree 洛谷 P3690

[模板]Link Cut Tree 思路: LCT模板: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 300005 int n,m,val[maxn]; int top,ch[maxn][2],f[maxn],xr[maxn],q[maxn],rev[maxn]; inline void in(int &now) { int if_z=1;now=0; char Cget=getchar(); while

【leetcode】Construct Binary Tree from Preorder and Inorder Traversal

问题: 给定二叉树的前序和中序遍历,重构这课二叉树. 分析: 前序.中序.后序都是针对于根结点而言,所以又叫作先根.中根.后根(当然不是高跟). 前序:根  左 右 中序:左  根 右 对二叉树,我们将其进行投影,就会发现个有趣的事: 发现投影后的顺序,恰好是中序遍历的顺序,这也就是为什么在构造二叉树的时候,一定需要知道中序遍历,因为中序遍历决定了结点间的相对左右位置关系.所以,对一串有序的数组,我们可以来构建二叉有序数,并通过中序遍历,就可以得到这个有序的数组. 既然中序遍历可以通过根结点将序

【LeetCode】103. Binary Tree Zigzag Level Order Traversal 解题报告

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51524241 Subject 出处:https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/ Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to ri

LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板

P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到y已经联通则无需连接. 2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在. 3:后接两个整数(x,y),代表将点x上的权值变成y. 输入输出

P3690 【模板】Link Cut Tree (动态树)

P3690 [模板]Link Cut Tree (动态树) https://www.luogu.org/problemnew/show/P3690 分析: LCT模板 代码: 注意一下cut! 1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 const int N = 300100; 7 8 int val[N],fa[N],ch[N][2],rev[N],sum[N],st[N],top;

【leetcode】145. Binary Tree Postorder Traversal

题目如下: 解题思路:凑数题+3,搞不懂为什么本题的难度是Hard,而[leetcode]590. N-ary Tree Postorder Traversal是Medium. 代码如下: # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solutio

【LeetCode】Balanced Binary Tree 解题报告

[题目] Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1. [说明] 不是很难,思路大家可能都会想到用递归,分别判断左右

【LeetCode】145. Binary Tree Postorder Traversal 解题报告

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51494797 Subject 出处:https://leetcode.com/problems/binary-tree-postorder-traversal/ Hard 级别 Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary tree