ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[冲刺国赛2022] 模拟赛1

2022-05-06 23:03:32  阅读:162  来源: 互联网

标签:10 矩形 ... int 国赛 leq 冲刺 2022 include


铃原露露

题目描述

给定一棵有根树,根是 \(1\),顶点编号是 \(1,2...n\),对于 \(2\leq i\leq n\) 有 \(f_i\) 是 \(i\) 的父亲,\(a_1...a_n\) 是 \(1...n\) 的一个排列。

有 \(m\) 次询问,每次询问给出 \(l,r\),问有多少个二元组 \(L,R\),满足 \(l\leq L\leq R\leq r\),且对任意 \(L\leq a_x\leq a_y\leq R\),满足树上的最近公共祖先 \(z\) 满足 \(L\leq a_z\leq R\)

\(n,m\leq 2\cdot 10^5\)

解法

从整体的角度来考虑限制,也就是任取两个点 \(x,y\) ,如果 \(x\leq z\leq y\),那么 \((x,y)\) 对所有 \((l,r)\) 的合法性没有影响;如果 \(z<x\leq y\),那么它会使得 \(l\in(z,x],r\in[y,n]\) 的 \((l,r)\) 不合法;如果 \(x\leq y<z\),那么它会使得 \(l\in[1,x],r\in[y,z)\) 的 \((l,r)\) 不合法。

那么问题变成了有若干个矩形,我们不能取矩形中的点,每次问一个范围中可以取的点数是多少。

首先要减少矩形的数量,发现可以在 \(z\) 处统计所有的矩形,而且可以用树上启发式合并,根据包含关系在把某个点合并上来时只用考虑其前驱后继(与之类似的题目:事情的相似度

剩下的就是套路了,我们移动右端点,维护所有左端点的历史答案和。线段树要支持历史零点个数查询,我们只需要额外维护标记序列的最小值和取到这个最小值的数量即可,时间复杂度 \(O(n\log^2n)\)

总结

本题最出彩的地方是表示限制的方法,这种小处到整体的技巧很类似于贡献法。我一开始想虚树是不行的,因为本题不同 \((l,r)\) 的合法性之间有很大的联系,我没有利用到。

#include <cstdio>
#include <vector>
#include <iostream>
#include <set>
using namespace std;
const int M = 200005;
const int N = M<<2;
#define pb push_back
#define ll long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
void write(ll x)
{
	if(x>=10) write(x/10);
	putchar(x%10+'0');
}
int n,m,a[M],mi[N],mc[N],fl[N],ti[N],tc[N];
vector<int> g[M];set<int> s[M];ll ans[M],sum[N];
struct node{int l,r,c;};vector<node> v[M],q[M];
void add(int x,int y,int z)
{
	if(x<=z && z<=y) return ;
	if(z<x) v[y].pb({z+1,x,1});
	else v[y].pb({1,x,1}),v[z].pb({1,x,-1});
}
void dfs(int u,int fa)
{
	s[u].insert(a[u]);
	for(int &v:g[u]) if(v^fa)
	{
		dfs(v,u);
		if(s[u].size()<s[v].size())
			swap(s[u],s[v]);
		for(int x:s[v])
		{
			auto it=s[u].lower_bound(x);
			if(it!=s[u].end()) add(x,*it,a[u]);
			if(it!=s[u].begin()) it--,add(*it,x,a[u]);
		}
		for(int x:s[v]) s[u].insert(x);
	}
}
void up(int i)
{
	mi[i]=min(mi[i<<1],mi[i<<1|1]);mc[i]=0;
	if(mi[i]==mi[i<<1]) mc[i]+=mc[i<<1];
	if(mi[i]==mi[i<<1|1]) mc[i]+=mc[i<<1|1];
	sum[i]=sum[i<<1]+sum[i<<1|1];
}
void build(int i,int l,int r)
{
	if(l==r)
	{
		mi[i]=mc[i]=1;
		return ;
	}
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	up(i);
}
void down(int i)
{
	int ls=i<<1,rs=i<<1|1;
	//
	if(mi[ls]+ti[i]==0) sum[ls]+=1ll*tc[i]*mc[ls];
	mi[ls]+=fl[i];
	if(ti[i]+fl[ls]<ti[ls])
		ti[ls]=ti[i]+fl[ls],tc[ls]=0;
	if(ti[i]+fl[ls]==ti[ls]) tc[ls]+=tc[i];
	fl[ls]+=fl[i];
	//
	if(mi[rs]+ti[i]==0) sum[rs]+=1ll*tc[i]*mc[rs];
	mi[rs]+=fl[i];
	if(ti[i]+fl[rs]<ti[rs])
		ti[rs]=ti[i]+fl[rs],tc[rs]=0;
	if(ti[i]+fl[rs]==ti[rs]) tc[rs]+=tc[i];
	fl[rs]+=fl[i];
	//
	ti[i]=tc[i]=fl[i]=0;
}
void add(int i,int l,int r,int L,int R,int c)
{
	if(L>r || l>R) return ;
	if(L<=l && r<=R)
	{
		mi[i]+=c;fl[i]+=c;
		if(mi[i]==0) sum[i]+=mc[i];
		if(fl[i]<ti[i]) ti[i]=fl[i],tc[i]=0;
		if(fl[i]==ti[i]) tc[i]++;
		return ;
	}
	int mid=(l+r)>>1;down(i);
	add(i<<1,l,mid,L,R,c);
	add(i<<1|1,mid+1,r,L,R,c);
	up(i);
}
int ask(int i,int l,int r,int L,int R)
{
	if(L>r || l>R) return 0;
	if(L<=l && r<=R) return sum[i];
	int mid=(l+r)>>1;down(i);
	return ask(i<<1,l,mid,L,R)
	+ask(i<<1|1,mid+1,r,L,R);
}
signed main()
{
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=2;i<=n;i++)
		g[read()].pb(i);
	dfs(1,0);
	for(int i=1;i<=n;i++) v[i].pb({i,i,-1});//在 r=i 时激活 l=i 
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int l=read(),r=read();
		q[r].pb({l,r,i});
	}
	for(int i=1;i<=n;i++)
	{
		add(1,1,n,1,n,1);
		for(auto &x:v[i])
			add(1,1,n,x.l,x.r,x.c);
		add(1,1,n,1,n,-1);//前面保证>=1,只在这里做一次历史 
		for(auto &x:q[i])
			ans[x.c]+=ask(1,1,n,x.l,x.r);
	}
	for(int i=1;i<=m;i++)
		write(ans[i]),puts("");
}

标签:10,矩形,...,int,国赛,leq,冲刺,2022,include
来源: https://www.cnblogs.com/C202044zxy/p/16236683.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有