把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3722 [AH2017/HNOI2017]影魔

题面传送门
线段树是什么勾八玩意儿。
看到题一头雾水,然后看了看部分分,有个奇怪的\(p1=2p2\)
略微撕烤一下这档分怎么做,大概就是第一种贡献可以看作两个第二个贡献的叠加。
于是我们可以把题意转化一下:
第一种贡献:如果一个区间\([l,r]\),满足\(a_r\)大于\([l+1,r-1]\)最大值,那么贡献\(p2\),如果\(a_l\)也是这样,叠加贡献\(p2\)
第二种贡献:如果一个区间\([l,r]\),满足\(a_r,a_l\)均大于区间中的数,那么贡献\(p1-2p2\)
第一种贡献显然是可算的,直接单调栈然后扫描线,第二种贡献看上去就不是那么可做。
证明一个结论:造成第二种贡献的区间个数是\(O(n)\)的。
考虑扫描线维护单调栈的过程,如果\(a_i\)与前面的一个\(a_l\)构成了上面这种区间,要么\(a_l>a_i\),这对每个数来说停止弹栈,是\(O(n)\)的,第二种是\(a_l<a_i\),那么接下来\(a_l\)被弹出,也是\(O(n)\)的,所以这个贡献在扫描线的时候暴力修改就好了。
时间复杂度\(O(n\log n)\),写了个树状数组才跑起来像个log样。
code:


#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (200000+5)
#define M ((N<<2)+5)
#define Ks (12+5)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;struct Ques{int w,id;};vector<Ques> S[N];
int n,m,k,L[N],R[N],X[N],Y[N],z,p1,p2,st[N],H,A[N];ll Ans[N];
namespace Tree{
	ll F1[N],F2[N];I void I1(int x,int y){while(x<=n) F1[x]+=y,x+=x&-x;}I void I2(int x,int y){while(x<=n) F2[x]+=y,x+=x&-x;}
	I ll Q1(int x){ll Ans=0;while(x) Ans+=F1[x],x-=x&-x;return Ans;}I ll Q2(int x){ll Ans=0;while(x) Ans+=F2[x],x-=x&-x;return Ans;}
	I void Ins(int x,int y,int z){I1(x,z);I2(x,z*(x-1));I1(y+1,-z);I2(y+1,-z*y);}
	I ll Qry(int x,int y){return Q1(y)*y-Q2(y)-Q1(x-1)*(x-1)+Q2(x-1);}
}
int main(){
	freopen("1.in","r",stdin);
	int i,j;scanf("%d%d%d%d",&n,&m,&p1,&p2);for(i=1;i<=n;i++) scanf("%d",&A[i]),L[i]=0,R[i]=n+1;H=0;for(i=1;i<=n;i++) {while(H&&A[st[H]]<A[i]) R[st[H--]]=i;L[i]=st[H];st[++H]=i;}
	for(i=1;i<=m;i++) scanf("%d%d",&X[i],&Y[i]),S[Y[i]].PB((Ques){X[i],i});H=0;for(i=1;i<=n;i++){
		Tree::Ins(max(L[i],1),i-1,p2);while(H&&A[st[H]]<A[i]) Tree::Ins(st[H],st[H],p1-2*p2),H--;H&&(Tree::Ins(st[H],st[H],p1-2*p2),0);st[++H]=i;for(Ques d:S[i]) Ans[d.id]=Tree::Qry(d.w,i);
	}for(i=1;i<=n;i++) S[i].clear();for(i=1;i<=m;i++) S[X[i]].PB((Ques){Y[i],i});Me(Tree::F1,0);Me(Tree::F2,0);
	for(i=n;i;i--){Tree::Ins(i+1,min(n,R[i]),p2);for(Ques d:S[i]) Ans[d.id]+=Tree::Qry(i,d.w);} for(i=1;i<=m;i++) printf("%lld\n",Ans[i]);
}
posted @ 2022-05-28 21:32  275307894a  阅读(24)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end