CF1677E Tokitsukaze and Beautiful Subsegments

(题目传送门)

你就算再怎么套路我也做不出来……

看到 maxak,根据套路想到用单调栈处理出 ai 左边第一个比它大的位置 prei,右边第一个比它大的位置 nxti。枚举最大值 ai 考虑它的贡献,显然若存在 j,k 满足 nxti<j,k<preiaj×ak=ai,那么记 x=min(i,j,k),y=max(i,j,k),那么 (j,k) 就可以对区间 (prei,x][y,nxti) 产生贡献。显然满足这种条件的数对不超过 O(nlnn) 个,可以预处理出来。

将这个区间贡献看成矩形的赋值,这是难操作的,尝试转化成矩形加。发现不同的 maxai 的矩形不会相交,于是只需考虑单个 ai 内部的矩形。假设现在有若干数对 (x,y) 可以对 (prei,x][y,nxti) 产生贡献,矩形可能相交。你发现如果 xi<xjyi>yj 那么 (xi,yi) 就被 (xj,yj) 完全包含了,所以最后有用的数对必然满足 x1<x2<<xmy1<y2<<ym,这可以排序后单调栈求出。

将单个 ai 的矩形拆解后,画个图发现这样的矩形覆盖可以直接容斥变成矩形加。于是问题转化成了矩形加、矩形求和。将询问离线下来,扫描线+树状数组维护即可。

#include<bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
using namespace std;

const int N=2e5+10,M=1e6+10;

int n,m,p[N],q[N];
int sta[N],top,pre[N],nxt[N];
vector <pii> P[N],tmp;
vector < array<int,4> > Q[N];
vector < array<int,3> > mat[N];
LL ans[M];

struct BIT
{
	LL c1[N],c2[N];

	void add(int x,int y)
	{
		for(int i=x; i<=n; i+=(i&-i))
		{
			c1[i]+=(LL)y;
			c2[i]+=1LL*y*x;
		}
	}

	LL ask(int x)
	{
		LL res=0;
		for(int i=x; i; i-=(i&-i))
			res+=1LL*(x+1)*c1[i]-c2[i];
		return res;
	}

	void update(int l,int r,int v){add(l,v);add(r+1,-v);}

	LL query(int l,int r){return ask(r)-ask(l-1);}
}T1,T2;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++)
		scanf("%d",&p[i]),q[p[i]]=i;

	for(int i=1; i<=n; i++)
	{
		while(top && p[sta[top]]<p[i])
			top--;
		pre[i]=sta[top];  sta[++top]=i;
	}
	sta[top=0]=n+1;
	for(int i=n; i>=1; i--)
	{
		while(top && p[sta[top]]<p[i])
			top--;
		nxt[i]=sta[top];  sta[++top]=i;
	}

	for(int i=1; i*(i+1)<=n; i++)
		for(int j=i+1; i*j<=n; j++)
			if(pre[q[i*j]]<min(q[i],q[j]) && nxt[q[i*j]]>max(q[i],q[j]))
				P[q[i*j]].push_back({min({q[i],q[j],q[i*j]}),max({q[i],q[j],q[i*j]})});

	for(int i=1; i<=n; i++)
	{
		tmp.clear();
		tmp.push_back({pre[i],i-1});
		sort(P[i].begin(),P[i].end(),[](pii A,pii B)
			{return A.first==B.first? A.second>B.second:A.first<B.first;});
		for(auto [l,r]:P[i])
		{
			while(r<=tmp.back().second)
				tmp.pop_back();
			tmp.push_back({l,r});
		}
		for(int j=1; j<tmp.size(); j++)
		{
			mat[tmp[j].second].push_back({tmp[j-1].first+1,tmp[j].first,1});
			mat[nxt[i]].push_back({tmp[j-1].first+1,tmp[j].first,-1});
		}
	}		

	for(int i=1; i<=m; i++)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		Q[r].push_back({l,r,i,1});
		Q[l].push_back({l,r,i,-1});
	}

	for(int i=1; i<=n; i++)
	{
		for(auto [l,r,op]:mat[i])
		{
			T1.update(l,r,op);
			T2.update(l,r,op*(i-1));
		}
		for(auto [l,r,id,op]:Q[i])
			ans[id]=1LL*op*i*T1.query(l,r)-T2.query(l,r);
	}

	for(int i=1; i<=m; i++)
		printf("%lld\n",ans[i]);

	return 0;
}
posted @   xishanmeigao  阅读(5)  评论(0编辑  收藏  举报
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示