BZOJ 4826: [Hnoi2017]影魔 单调栈 主席树
https://www.lydsy.com/JudgeOnline/problem.php?id=4826
年少不知空间贵,相顾mle空流泪。
和上一道主席树求的东西差不多,求两种对
1. max(a[(i,j)])<min(a[i],a[j]),[i,j]这一对贡献p1.
2. max(a[(i,j)])在a[i],a[j]之间,[i,j]这一对贡献p2.
第一种和bzoj3956那道一样,但是因为是排列所以没必要去重了。
第二种同样是单调栈求lp,rp,每个位置的lp分别和[ i+1 , rp-1 ], rp分别和[ lp+1 , i-1 ], 构成了贡献p2的数对。
因此贡献为p2的数对要区间修改,因为方便(不用downdata)(其实是因为我抄的代码就是标记永久化)所以写了标记永久化,标记永久化真的挺好用的嘻嘻。
感觉写了这道题终于有点摸到主席树的门路了,其实就是找和维护两个区间进行限制的值(找和维护一个二维块),一层线段树一层前缀和(只是有传递性不一定是实际意义的和)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 #define LL long long 8 const int maxn=200010; 9 LL n,m,p1,p2; 10 LL a[maxn]={},sta[maxn]={},tail=0; 11 LL lp[maxn]={},rp[maxn]={},rt[maxn]={}; 12 LL lc[maxn*64]={},rc[maxn*64]={},siz[maxn*64]={},ad[maxn*64]={},tot=0; 13 struct nod{ 14 LL x,l,r,v; 15 }e[maxn*4]; 16 LL cnt=0; 17 bool mcmp(nod aa,nod bb){ return aa.x<bb.x; } 18 LL read(){ 19 LL w=0,f=1;char ch=getchar(); 20 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 21 while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();} 22 return w*f; 23 } 24 void build(LL &x,LL y,LL l,LL r,LL z,LL zl,LL zr){ 25 x=++tot;lc[x]=lc[y];rc[x]=rc[y];ad[x]=ad[y];siz[x]=siz[y]+z*(zr-zl+1); 26 if(zl==l&&r==zr){ad[x]+=z;return;} 27 LL mid=(l+r)/2; 28 if(zr<=mid)build(lc[x],lc[y],l,mid,z,zl,zr); 29 else if(zl>mid) build(rc[x],rc[y],mid+1,r,z,zl,zr); 30 else { 31 build(lc[x],lc[y],l,mid,z,zl,mid); 32 build(rc[x],rc[y],mid+1,r,z,mid+1,zr); 33 } 34 } 35 LL getsum(LL x,LL y,LL l,LL r,LL zl,LL zr){ 36 if(zl==l&&r==zr)return siz[y]-siz[x]; 37 LL mid=(l+r)/2,ans=(ad[y]-ad[x])*(zr-zl+1); 38 if(zr<=mid)return ans+getsum(lc[x],lc[y],l,mid,zl,zr); 39 else if(zl>mid) return ans+getsum(rc[x],rc[y],mid+1,r,zl,zr); 40 else { 41 return ans+getsum(lc[x],lc[y],l,mid,zl,mid)+getsum(rc[x],rc[y],mid+1,r,mid+1,zr); 42 } 43 } 44 //以上主席树 45 inline void fir(){ 46 LL i; 47 a[0]=a[n+1]=(1<<30); 48 for(i=1;i<=n;++i){ 49 while(a[sta[tail]]<=a[i])tail--; 50 lp[i]=sta[tail];sta[++tail]=i; 51 } 52 sta[0]=n+1;tail=0; 53 for(i=n;i>0;--i){ 54 while(a[sta[tail]]<=a[i])tail--; 55 rp[i]=sta[tail];sta[++tail]=i; 56 } 57 } 58 inline void init(LL x,LL l,LL r,LL v){ 59 e[++cnt].x=x;e[cnt].l=l;e[cnt].r=r;e[cnt].v=v; 60 } 61 inline void fir2(){ 62 LL i,j; 63 for(i=1;i<=n;++i){ 64 if(lp[i]!=0&&rp[i]!=n+1)init(lp[i],rp[i],rp[i],p1); 65 if(i<n)init(i,i+1,i+1,p1); 66 if(lp[i]!=0&&rp[i]-i>1)init(lp[i],i+1,rp[i]-1,p2); 67 if(rp[i]!=n+1&&i-lp[i]>1)init(rp[i],lp[i]+1,i-1,p2); 68 } 69 sort(e+1,e+cnt+1,mcmp); 70 for(i=j=1;i<=n;++i){ 71 rt[i]=rt[i-1]; 72 for(;e[j].x==i&&j<=cnt;++j)build(rt[i],rt[i],1,n,e[j].v,e[j].l,e[j].r); 73 } 74 } 75 int main(){ 76 LL i,x,y,ans=0; 77 n=read();m=read();p1=read();p2=read(); 78 for(i=1;i<=n;++i)a[i]=read(); 79 fir(); fir2(); 80 for(i=1;i<=m;++i){ 81 x=read();y=read(); 82 if(x>y)swap(x,y); 83 ans=getsum(rt[x-1],rt[y],1,n,x,y); 84 printf("%lld\n",ans); 85 } 86 return 0; 87 }