【JOI2020 Final】火灾

【JOI2020 Final】火灾

Description

给定一个长为\(N\)的序列\(S_i\),刚开始为时刻\(0\)

定义\(t\)时刻第\(i\)个数为\(S_i(t)\),那么:

\[\left\{ \begin{array}{ll} S_0(t)=0\\S_i(0)=S_i\\S_i(t)=\max\{S_{i-1}(t-1),S_i(t-1)\} \end{array} \right.\]

你将对\(Q\)个操作进行评估,第\(j\)个操作让时刻\(T_j\)时的区间\([L_j,R_j]\)全部变为\(0\)

执行一个操作需要一定的代价,执行第 \(j\) 个操作需要以下的代价:\(\sum\limits_{k=L_j}^{R_j}S_k(T_j)\)

求每个操作需要的代价

注意:每个操作都是独立的

Input

第一行两个整数\(N,Q\)代表序列长度和操作数

第二行\(N\)个整数\(S_i\)代表这个序列

接下来\(Q\)行每行三个整数\(T_j,L_j,R_j\)代表一个操作

Output

\(Q\)行每行一个整数代表这个操作需要的代价

Sample Input

5 5
9 3 2 6 5
1 1 3
2 1 5
3 2 5
4 3 3
5 3 5

Sample Output

21
39
33
9
27

Data Constraint

\(1\le N,Q,T_i\le 2*10^5\)

Solution

比较有意思的数据结构题

以横坐标为位置,纵坐标为时间

把一个数作为最大值出现的坐标写出来

可以发现构成了一个平行四边形

其坐标可以通过单调栈得到

然后我们将平行四边形变为一个大三角形减去两个小三角形

可以发现,这里的三角形都是等腰直角三角形,而且底边都在\(x\)轴上

所以我们只需要记录右上角的顶点

然后对询问差分,即变为两条射线,对每条射线统计经过位置的权值之和

做一点简单的观察,可以发现射线跟三角形的关系有三种

1.不交

2.射线顶点在三角形内部

3.射线完整穿过了三角形

后面两种都可以通过写出\(x,y\)的关系,然后扫描线+树状数组维护

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define N 200010

LL ans[N];
int n,m,a[N],le[N],ri[N],q[N],top,tot,cnt;
struct node{int x,y,v;}op[N*3];
struct mode{int x,y,pos,k;}ask[N*2];
struct BIT{
	LL sum[N*2];
	int lowbit(int x){return -x&x;}
	void change(int x,LL v){for(;x<=2*n+5;x+=lowbit(x))sum[x]+=v;}
	LL query(int x){LL res=0;for(;x;x-=lowbit(x))res+=sum[x];return res;}
	void clear(){memset(sum,0,sizeof(sum));}
}t1,t2;

bool cmp1(node x,node y){return x.x<y.x;}

bool cmp2(mode x,mode y){return x.x<y.x;}

int main(){
	scanf("%d%d",&n,&m);
	F(i,1,n)scanf("%d",&a[i]);
	a[0]=a[n+1]=2147483647;
	q[top=1]=0;
	F(i,1,n){
		while(a[i]>=a[q[top]]&&top)top--;
		le[i]=q[top];q[++top]=i;
	}
	q[top=1]=n+1;
	Fd(i,n,1){
		while(a[i]>a[q[top]]&&top)top--;
		ri[i]=q[top];q[++top]=i;
	}
	F(i,1,n){
		// (i,0) (i,i-li-1) (ri-1,ri-i-1) (ri-1,ri-li-2)
		int tmp=(le[i]?0:n);
		if(ri[i]-le[i]-2+tmp>=0)op[++tot]=(node){ri[i]-1,ri[i]-le[i]-2+tmp,a[i]};
		if(ri[i]-i-2>=0)op[++tot]=(node){ri[i]-1,ri[i]-i-2,-a[i]};
		if(i-le[i]-2+tmp>=0)op[++tot]=(node){i-1,i-le[i]-2+tmp,-a[i]};
	}
	F(i,1,m){
		int t,l,r;
		scanf("%d%d%d",&t,&l,&r);
		ask[++cnt]=(mode){r,t,i,1};
		ask[++cnt]=(mode){l-1,t,i,-1};
	}
	// (x-y,0) (x,0) (x,y)
	sort(op+1,op+tot+1,cmp1);
	sort(ask+1,ask+cnt+1,cmp2);
	int h=tot+1;
	Fd(i,cnt,1){
		while(op[h-1].x>ask[i].x&&h-1>=1){
			h--;
			t1.change(op[h].x-op[h].y+n,1ll*(op[h].x-op[h].y)*op[h].v);
			t2.change(op[h].x-op[h].y+n,op[h].v);
		}
		LL tmp1=t1.query(ask[i].x-ask[i].y+n),tmp2=t2.query(ask[i].x-ask[i].y+n);
		ans[ask[i].pos]+=(-tmp1+tmp2*(ask[i].x-ask[i].y+1))*ask[i].k;
	}
	t1.clear();t2.clear();
	h=0;
	F(i,1,cnt){
		while(op[h+1].x<=ask[i].x&&h+1<=tot){
			h++;
			t1.change(op[h].y+5,1ll*op[h].y*op[h].v);
			t2.change(op[h].y+5,op[h].v);
		}
		LL tmp1=t1.query(2*n+5)-t1.query(ask[i].y-1+5),tmp2=t2.query(2*n+5)-t2.query(ask[i].y-1+5);
		ans[ask[i].pos]+=(tmp1-tmp2*(ask[i].y-1))*ask[i].k;
	}
	F(i,1,m)printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2022-10-26 20:53  冰雾  阅读(29)  评论(0编辑  收藏  举报