标签:size ret printf lib 大于 sum tac str hal
为了这道题还特地去学了标记永久化,可能对于区间修改主席树或者树套树比较有用吧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;
}
标签:size ret printf lib 大于 sum tac str hal
原文地址:http://www.cnblogs.com/Hallmeow/p/8004806.html