[BZOJ 4826]影魔 區間修改主席樹 標記永久化
阿新 • • 發佈:2017-12-08
brush sca ostream www cpp pad stream i+1 return
為了這道題還特地去學了標記永久化,可能對於區間修改主席樹或者樹套樹比較有用吧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]影魔 區間修改主席樹 標記永久化