P3722 [AH2017/HNOI2017] 影魔
P3722 [AH2017/HNOI2017] 影魔
题目背景
影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。
千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。
每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。
题目描述
奈文摩尔有
影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间
顺带一提,灵魂的战斗力组成一个
提示
对于
Solution:
题意简述:给定一个排列 ,对于 的三元组有以下两类贡献:
我们考虑对一个点
然后我们考虑如何刻画这个三元组的贡献:
所以:
这可太线段树了
我们开一颗主席树,以每个区间的左端点作为
if(i<n)E[i].emplace_back(i+1,i+1,p1); if((1<=l)&&(r<=n))E[l].emplace_back(r,r,p1); if((1<=l)&&(i+1<=r-1))E[l].emplace_back(i+1,r-1,p2); if((l+1<=i-1)&&(r<=n))E[r].emplace_back(l+1,i-1,p2);
然后每次查询就是
ans=T.query(T.rt[l-1],T.rt[r],1,n,l,r);
然后注意一个东西,由于我的主席树的下标是挂在询问上的,所以最好写标记永久化,不然不好写
Code
#include<bits/stdc++.h> #define int long long const int N=2e5+5; using namespace std; //Segment_Tree struct Segment_Tree{ int cnt; int rt[N]; struct Tree{ int ls,rs,val,tag; }t[N*64]; void insert(int &x,int y,int l,int r,int L,int R,int k) { t[x=++cnt]=t[y]; int len=(-max(L,l)+min(r,R)+1); t[x].val+=len*k; if(L<=l&&r<=R) { t[x].tag+=k; return ; } int mid=l+r>>1; if(L<=mid)insert(t[x].ls,t[y].ls,l,mid,L,R,k); if(mid<R) insert(t[x].rs,t[y].rs,mid+1,r,L,R,k); } int query(int x,int y,int l,int r,int L,int R) { if(!y)return 0; int len=(-max(L,l)+min(r,R)+1); if(L<=l&&r<=R) { return (-t[x].val+t[y].val); } int mid=l+r>>1,res=0; if(L<=mid)res+=query(t[x].ls,t[y].ls,l,mid,L,R); if(mid<R) res+=query(t[x].rs,t[y].rs,mid+1,r,L,R); res+=len*(-t[x].tag+t[y].tag); return res; } }T; int n,m,p1,p2; int a[N],st[N],L[N],R[N]; vector<tuple<int,int,int> >E[N]; void work() { cin>>n>>m>>p1>>p2; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); while(st[0]&&a[st[st[0]]]<a[i]){R[st[st[0]]]=i;st[0]--;} L[i]=st[st[0]]; st[++st[0]]=i; } while(st[0]){R[st[st[0]]]=n+1;st[0]--;} for(int i=1;i<=n;i++) { int l=L[i],r=R[i]; if(i<n)E[i].emplace_back(i+1,i+1,p1); if((1<=l)&&(r<=n))E[l].emplace_back(r,r,p1); if((1<=l)&&(i+1<=r-1))E[l].emplace_back(i+1,r-1,p2); if((l+1<=i-1)&&(r<=n))E[r].emplace_back(l+1,i-1,p2); } for(int i=1;i<=n;i++) { T.rt[i]=T.rt[i-1]; for(auto [l,r,w] : E[i]) { T.insert(T.rt[i],T.rt[i],1,n,l,r,w); } } for(int i=1,l,r;i<=m;i++) { scanf("%lld%lld",&l,&r); int ans=T.query(T.rt[l-1],T.rt[r],1,n,l,r); printf("%lld\n",ans); } } #undef int int main() { //freopen("P3722.in","r",stdin);freopen("P3722.out","w",stdout); work(); return 0; }