[BZOJ 4826]影魔 区间修改主席树 标记永久化
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 4826]影魔 区间修改主席树 标记永久化相关的知识,希望对你有一定的参考价值。
为了这道题还特地去学了标记永久化,可能对于区间修改主席树或者树套树比较有用吧OvO
我们可以把答案分为两部分:p1造成的和p2造成的
我们枚举序列,用单调栈求出序列每一个位置i,左右边第一个比它大的L,R
开三棵主席树tree1 tree2 tree3
把L扔进tree1的R位置(单点+1),L+1~i-1扔进tree2的R位置,i+1~R-1扔进tree3的L位置(区间+1)
然后询问[l,r]的时候,求出三棵区间主席树
p1造成的贡献为区间tree1内大于等于L的个数
p2造成的贡献为区间tree2内大于等于L的个数和区间tree3内小于等于R的个数
因为要建主席树,所以我们先拿vector存一下每个位置需要往里扔什么,然后再扫一遍到一个点全扔进去(注意以这个点的最后一个版本为此位置的主席树)
还有要开long long!!!
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #include<vector> #define N 301000 #define LL long long using namespace std; int n,m,p1,p2; int a[N]; int stack[N]; struct xixi{ int l,r; }cun[N]; vector<int> add1[N]; vector<xixi> add_l[N],add_r[N]; struct haha{ int lc,rc,sum; }tree1[N*25],tree_l[N*25],tree_r[N*25]; int size1,size_l,size_r; int root1[N],root_l[N],root_r[N]; int biao_r[N*25],biao_l[N*25]; void update1(int &rt,int l,int r,int pos){ tree1[++size1]=tree1[rt]; int t=size1;tree1[t].sum++;rt=t; if(l==r) return; int mid=(l+r)>>1; if(pos<=mid) update1(tree1[rt].lc,l,mid,pos); else update1(tree1[rt].rc,mid+1,r,pos); tree1[rt].sum=tree1[tree1[rt].lc].sum+tree1[tree1[rt].rc].sum; } void update_r(int old,int &rt,int l,int r,int xl,int xr){ if(!rt) rt=++size_r; if(l>=xl&&r<=xr){ biao_r[rt]=biao_r[old]+1; tree_r[rt].sum=tree_r[old].sum+(r-l+1); tree_r[rt].lc=tree_r[old].lc; tree_r[rt].rc=tree_r[old].rc; return; } tree_r[rt].sum=tree_r[old].sum+(xr-xl+1); int mid=(l+r)>>1; if(xr<=mid){ update_r(tree_r[old].lc,tree_r[rt].lc,l,mid,xl,xr); tree_r[rt].rc=tree_r[old].rc; } else{ if(xl>mid){ update_r(tree_r[old].rc,tree_r[rt].rc,mid+1,r,xl,xr); tree_r[rt].lc=tree_r[old].lc; } else{ update_r(tree_r[old].lc,tree_r[rt].lc,l,mid,xl,mid); update_r(tree_r[old].rc,tree_r[rt].rc,mid+1,r,mid+1,xr); } } } void update_l(int old,int &rt,int l,int r,int xl,int xr){ if(!rt) rt=++size_l; if(l>=xl&&r<=xr){ biao_l[rt]=biao_l[old]+1; tree_l[rt].sum=tree_l[old].sum+(r-l+1); tree_l[rt].lc=tree_l[old].lc; tree_l[rt].rc=tree_l[old].rc; return; } tree_l[rt].sum=tree_l[old].sum+(xr-xl+1); int mid=(l+r)>>1; if(xr<=mid){ update_l(tree_l[old].lc,tree_l[rt].lc,l,mid,xl,xr); tree_l[rt].rc=tree_l[old].rc; } else{ if(xl>mid){ update_l(tree_l[old].rc,tree_l[rt].rc,mid+1,r,xl,xr); tree_l[rt].lc=tree_l[old].lc; } else{ update_l(tree_l[old].lc,tree_l[rt].lc,l,mid,xl,mid); update_l(tree_l[old].rc,tree_l[rt].rc,mid+1,r,mid+1,xr); } } } int query1(int rtl,int rtr,int l,int r,int pos){ if(!rtr) return 0; if(r<pos) return 0; if(l==r) return tree1[rtr].sum-tree1[rtl].sum; int mid=(l+r)>>1; if(pos<=mid){ return query1(tree1[rtl].lc,tree1[rtr].lc,l,mid,pos)+tree1[tree1[rtr].rc].sum-tree1[tree1[rtl].rc].sum; } else return query1(tree1[rtl].rc,tree1[rtr].rc,mid+1,r,pos); } int query_r(int rtl,int rtr,int ad,int l,int r,int pos){ if(r<pos) return 0; int tempad=biao_r[rtr]-biao_r[rtl]; if(l==r||l>=pos){ return tree_r[rtr].sum-tree_r[rtl].sum+(ad)*(r-l+1); } int mid=(l+r)>>1; if(pos<=mid){ return query_r(tree_r[rtl].lc,tree_r[rtr].lc,ad+tempad,l,mid,pos)+query_r(tree_r[rtl].rc,tree_r[rtr].rc,ad+tempad,mid+1,r,pos); } else return query_r(tree_r[rtl].rc,tree_r[rtr].rc,ad+tempad,mid+1,r,pos); } int query_l(int rtl,int rtr,int ad,int l,int r,int pos){ if(l>pos) return 0; int tempad=biao_l[rtl]-biao_l[rtr]; if(l==r||r<=pos){ return tree_l[rtl].sum-tree_l[rtr].sum+(ad)*(r-l+1); } int mid=(l+r)>>1; if(pos>mid){ return query_l(tree_l[rtl].lc,tree_l[rtr].lc,ad+tempad,l,mid,pos)+query_l(tree_l[rtl].rc,tree_l[rtr].rc,ad+tempad,mid+1,r,pos); } else return query_l(tree_l[rtl].lc,tree_l[rtr].lc,ad+tempad,l,mid,pos); } int main(){ scanf("%d%d%d%d",&n,&m,&p1,&p2); pos(i,1,n) scanf("%d",&a[i]); stack[0]=1; pos(i,1,n){ while(stack[0]>1&&a[stack[stack[0]-1]]<a[i]) stack[0]--; if(stack[0]==1) cun[i].l=0; else cun[i].l=stack[stack[0]-1]; stack[stack[0]++]=i; } stack[0]=1; pos2(i,n,1){ while(stack[0]>1&&a[stack[stack[0]-1]]<a[i]) stack[0]--; if(stack[0]==1) cun[i].r=n+1; else cun[i].r=stack[stack[0]-1]; stack[stack[0]++]=i; } pos(i,1,n){ int l=cun[i].l,r=cun[i].r; if(l!=0) add1[r].push_back(l); if(i-1>=l+1&&r<=n) add_r[r].push_back((xixi){l+1,i-1}); if(r-1>=i+1&&l>=1) add_l[l].push_back((xixi){i+1,r-1}); } pos(i,1,n){ int k; k=add1[i].size()-1; if(k<0) root1[i]=root1[i-1]; else{ int t1=root1[i-1],t2; pos(j,0,k){ t2=t1; update1(t2,1,n,add1[i][j]); t1=t2; } root1[i]=t1; } k=add_r[i].size()-1; if(k<0) root_r[i]=root_r[i-1]; else{ int t1=root_r[i-1],t2(0); pos(j,0,k){ update_r(t1,t2,1,n,add_r[i][j].l,add_r[i][j].r); t1=t2;t2=0; } root_r[i]=t1; } } pos2(i,n,1){ int k=add_l[i].size()-1; if(k<0){ root_l[i]=root_l[i+1]; } else{ int t1=root_l[i+1],t2(0); pos(j,0,k){ update_l(t1,t2,1,n,add_l[i][j].l,add_l[i][j].r); t1=t2;t2=0; } root_l[i]=t1; } } LL ans(0); pos(i,1,m){ ans=0; int x,y;scanf("%d%d",&x,&y); ans+=(query1(root1[x-1],root1[y],1,n,x)+(y-x))*1ll*p1; ans+=query_r(root_r[x-1],root_r[y],0,1,n,x)*1ll*p2; ans+=query_l(root_l[x],root_l[y+1],0,1,n,y)*1ll*p2; printf("%lld\\n",ans); } return 0; }
以上是关于[BZOJ 4826]影魔 区间修改主席树 标记永久化的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 4826: [Hnoi2017]影魔 单调栈 主席树