BZOJ 4826 [Hnoi2017]影魔 ——扫描线 单调栈
首先用单调栈和扫描线处理出每一个数左面最近的比他大的数在$l[i]$,右面最近的比他大的数$r[i]$。
然后就可以考虑每种贡献是在什么时候产生的。
1、$(l[i],r[i])$产生$p1$的贡献
2、$([l[i]]-[i-1],i)$产生$p2$的贡献
3、$(i,[i+1]-[r[i]])$产生$p2$的贡献。
然后发现在笛卡尔坐标系中是一些线段和点,然后平行与扫描线的比较好解决。
但是垂直的就比较麻烦了。
然后有人用六棵主席树做过去了,也有人用四棵。
其实只要线段树分两次扫一遍就好了。
#include <map> #include <ctime> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define maxn 200005 struct Options{ int opt; //1 add 0 query int x,y,z,d,id; Options() {} Options(int _opt,int _x,int _y,int _z,int _d) {opt=_opt;x=_x;y=_y;z=_z;d=_d;} void print() { printf("Opt %d ( %d , %d , %d ) ID %d D: %d\n",opt,x,y,z,id,d); } }q[maxn<<3]; int n,m,p1,p2,a[maxn],cnt=0,sta[maxn],top,l[maxn],r[maxn],_l[maxn],_r[maxn]; ll ans[maxn],sum[maxn<<3],mark[maxn<<3]; bool cmp1(Options a,Options b) {return a.x==b.x?a.opt>b.opt:a.x<b.x;} bool cmp2(Options a,Options b) {return a.y==b.y?a.opt>b.opt:a.y<b.y;} void update(int o) {sum[o]=sum[o<<1]+sum[o<<1|1];} void pushdown(int o,int l,int r) { if (mark[o]!=0) { int mid=l+r>>1; sum[o<<1]+=(mid-l+1)*mark[o]; sum[o<<1|1]+=(r-mid)*mark[o]; mark[o<<1]+=mark[o]; mark[o<<1|1]+=mark[o]; mark[o]=0; } } void modify(int o,int l,int r,int L,int R,int f) { if (L<=l&&r<=R) { mark[o]+=f; sum[o]+=(r-l+1)*f; return; } int mid=l+r>>1;pushdown(o,l,r); if (L<=mid) modify(o<<1,l,mid,L,R,f); if (R>mid) modify(o<<1|1,mid+1,r,L,R,f); update(o); } ll query(int o,int l,int r,int L,int R) { if (L<=l&&r<=R) return sum[o]; int mid=l+r>>1;pushdown(o,l,r); if (R<=mid) return query(o<<1,l,mid,L,R); if (L>mid) return query(o<<1|1,mid+1,r,L,R); return query(o<<1,l,mid,L,R)+query(o<<1|1,mid+1,r,L,R); } int main() { scanf("%d%d%d%d",&n,&m,&p1,&p2); F(i,1,n) scanf("%d",&a[i]); F(i,1,m) { int x,y; scanf("%d%d",&_l[i],&_r[i]); x=_l[i];y=_r[i]; q[++cnt].id=i;q[cnt].d=1; q[cnt].x=y+1;q[cnt].y=y+1;q[cnt].opt=0; q[++cnt].id=i;q[cnt].d=1; q[cnt].x=x; q[cnt].y=x; q[cnt].opt=0; q[++cnt].id=i;q[cnt].d=-1;q[cnt].x=x; q[cnt].y=y+1;q[cnt].opt=0; q[++cnt].id=i;q[cnt].d=-1;q[cnt].x=y+1;q[cnt].y=x; q[cnt].opt=0; } F(i,1,n) { while(top&&a[sta[top]]<a[i]) top--; l[i]=sta[top]; sta[++top]=i; } sta[top=0]=n+1; D(i,n,1) { while(top&&a[sta[top]]<a[i]) top--; r[i]=sta[top]; sta[++top]=i; } F(i,1,n-1) { q[++cnt].opt=1;q[cnt].x=i+1;q[cnt].y=i+2;q[cnt].z=i+2;q[cnt].d=p1; } F(i,1,n) { q[++cnt]=Options(1,l[i]+1,r[i]+1,r[i]+1,p1); if (r[i]-1>=i+1) q[++cnt]=Options(1,l[i]+1,i+2,r[i],p2); } sort(q+1,q+cnt+1,cmp1); F(i,1,cnt) { switch(q[i].opt) { case 0:ans[q[i].id]+=q[i].d*query(1,1,n+2,1,q[i].y);break; case 1:modify(1,1,n+2,q[i].y,q[i].z,q[i].d);break; } } memset(sum,0,sizeof sum); memset(mark,0,sizeof mark);cnt=0; F(i,1,m) { int x,y;x=_l[i];y=_r[i]; q[++cnt].id=i;q[cnt].d=1; q[cnt].x=y+1;q[cnt].y=y+1;q[cnt].opt=0; q[++cnt].id=i;q[cnt].d=1; q[cnt].x=x; q[cnt].y=x; q[cnt].opt=0; q[++cnt].id=i;q[cnt].d=-1;q[cnt].x=x; q[cnt].y=y+1;q[cnt].opt=0; q[++cnt].id=i;q[cnt].d=-1;q[cnt].x=y+1;q[cnt].y=x; q[cnt].opt=0; } F(i,1,n) if (l[i]+1<=i-1) q[++cnt]=Options(1,l[i]+2,r[i]+1,i,p2); sort(q+1,q+cnt+1,cmp2); F(i,1,cnt) { switch(q[i].opt) { case 0:ans[q[i].id]+=q[i].d*query(1,1,n+2,1,q[i].x);break; case 1:modify(1,1,n+2,q[i].x,q[i].z,q[i].d);break; } } F(i,1,m) printf("%lld\n",ans[i]); }