[bzoj4826][HNOI2017]影魔
阿新 • • 發佈:2019-02-05
題目描述
影魔,奈文摩爾,據說有著一個詩人的靈魂。事實上,他吞噬的詩人靈魂早已成千上萬。千百年來,他收集了各式各樣
的靈魂,包括詩人、牧師、帝王、乞丐、奴隸、罪人,當然,還有英雄。每一個靈魂,都有著自己的戰鬥力,而影魔,靠
這些戰鬥力提升自己的攻擊。奈文摩爾有 n 個靈魂,他們在影魔寬廣的體內可以排成一排,從左至右標號 1 到 n。
第 i個靈魂的戰鬥力為 k[i],靈魂們以點對的形式為影魔提供攻擊力,對於靈魂對 i,j(i
做法
來看看到底要統計什麼?對於(i,j)滿足
max(a[i+1~j-1])
這樣有t1個,貢獻就是t1*p1。
如果
min(a[i],a[j])
這樣有t2個,貢獻就是t2*p2。
這個t2不是很好算,考慮轉化成
max(a[i+1~j-1]
然後減掉第一種情況
考慮對每個點i,求出left[i]和right[i]表示往左和往右第一個大於自己的位置。
對於第一種,列舉一個i作為較小的位置,較大的位置j只能是left[i]或right[i]。
對於第二種,列舉一個i作為較大的位置,較小的位置j只能夾在left[i]和i或i和right[i]之間。
第一種的式子 r]
第二種的式子
這個計算,拿個主席樹。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=200000+10,maxtot=5000000+10;
int a[maxn],left[maxn],right[maxn],ask[maxn][2 ],id[maxn];
int root[maxn],size[maxtot],tree[maxtot][2],sta[80];
ll num[maxtot],sum[maxtot];
ll cnt[maxn][2],ans,x,ans1,ans2,ans3;
int i,j,k,l,r,t,n,m,p1,p2,top,tot;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
bool cmp1(int x,int y){
return left[x]>left[y];
}
bool cmp2(int x,int y){
return right[x]<right[y];
}
int newnode(int x){
++tot;
tree[tot][0]=tree[x][0];
tree[tot][1]=tree[x][1];
size[tot]=size[x];
num[tot]=num[x];
sum[tot]=sum[x];
return tot;
}
void insert(int &x,int l,int r,int a,int p){
x=newnode(x);
if (l==r){
size[x]++;
num[x]+=(ll)l;
sum[x]+=p?(ll)right[l]:(ll)left[l];
return;
}
int mid=(l+r)/2;
if (a<=mid) insert(tree[x][0],l,mid,a,p);else insert(tree[x][1],mid+1,r,a,p);
size[x]=size[tree[x][0]]+size[tree[x][1]];
num[x]=num[tree[x][0]]+num[tree[x][1]];
sum[x]=sum[tree[x][0]]+sum[tree[x][1]];
}
void query(int x,int l,int r,int a,int b){
if (!x) return;
if (l==a&&r==b){
ans1+=size[x];
ans2+=num[x];
ans3+=sum[x];
return;
}
int mid=(l+r)/2;
if (b<=mid) query(tree[x][0],l,mid,a,b);
else if (a>mid) query(tree[x][1],mid+1,r,a,b);
else{
query(tree[x][0],l,mid,a,mid);
query(tree[x][1],mid+1,r,mid+1,b);
}
}
ll getsum(int n){
return (ll)n*(n+1)/2;
}
void write(ll x){
if (!x){
putchar('0');
putchar('\n');
return;
}
top=0;
while (x){
sta[++top]=x%10;
x/=10;
}
while (top) putchar('0'+sta[top--]);
putchar('\n');
}
int main(){
freopen("sf.in","r",stdin);freopen("sf.out","w",stdout);
n=read();m=read();p1=read();p2=read();
fo(i,1,n) a[i]=read();
fo(i,1,m) ask[i][0]=read(),ask[i][1]=read();
fo(i,1,n){
j=i-1;
while (j&&a[j]<a[i]) j=left[j];
left[i]=j;
}
fd(i,n,1){
j=i+1;
while (j<=n&&a[j]<a[i]) j=right[j];
right[i]=j;
}
fo(i,1,n) id[i]=i;
sort(id+1,id+n+1,cmp1);
tot=0;
j=1;
fd(i,n,1){
root[i]=root[i+1];
k=j-1;
while (k<n&&left[id[k+1]]==i) k++;
fo(t,j,k) insert(root[i],1,n,id[t],0);
j=k+1;
}
fo(i,1,m){
l=ask[i][0];r=ask[i][1];
ans1=ans2=ans3=0;
query(root[l],1,n,l,r);
cnt[i][0]+=ans1;
cnt[i][1]+=ans2-ans3-ans1;
ans1=(r-l+1)-ans1;
ans2=getsum(r)-getsum(l-1)-ans2;
cnt[i][1]+=ans2-(ll)ans1*l;
}
fo(i,1,tot)
tree[i][0]=tree[i][1]=size[i]=sum[i]=num[i]=0;
tot=0;
fo(i,1,n) id[i]=i;
sort(id+1,id+n+1,cmp2);
tot=0;
j=1;
fo(i,1,n){
root[i]=root[i-1];
k=j-1;
while (k<n&&right[id[k+1]]==i) k++;
fo(t,j,k) insert(root[i],1,n,id[t],1);
j=k+1;
}
fo(i,1,m){
l=ask[i][0];r=ask[i][1];
ans1=ans2=ans3=0;
query(root[r],1,n,l,r);
cnt[i][0]+=ans1;
cnt[i][1]+=ans3-ans2-ans1;
ans1=(r-l+1)-ans1;
ans2=getsum(r)-getsum(l-1)-ans2;
cnt[i][1]+=(ll)ans1*r-ans2;
}
fo(i,1,m){
l=ask[i][0];r=ask[i][1];
cnt[i][1]-=cnt[i][0];
ans=(ll)p1*cnt[i][0];
ans+=(ll)p2*cnt[i][1];
write(ans);
}
}