线段树
线段树是我的弱项
我们来看这一题:
要维护值得乘积
对 abc
如果a发生变化,那么我们要是知道b*c则只要加上a得增量就好了
基于着中国想法,我们使用了线段树。
我们一共开了7棵线段树!
先开三棵a,b,c
在我们的线段树所开的数组中记录的点seg[x]是,从点x到目前边界的 极差
线段树维护这个极差的和
而这个边界我们在不断地向后推,从而极差发生变化,用线段树维护。
同时,在维护了a,b,c每一次推边界后,以当前边界为右端点的区间的极差和后。
我们可以利用刚开始的思想维护出ab,ac,bc,abc的值
满足结合律,我们当然可以利用线段树!
而,如何在将边界向后推的过程中,维护变化的极差呢?
这里就要用到单调栈了!
我们枚举到一个新的边界,然后利用两个单调栈,得到左边第一个大于值他的索引l1,
第一个值小于他的索l2
那么显然,l1之内的极差要产生增加,l1之内的极差要减小
当然要先减去之前的值了,这个在维护单调栈时也能实现。
具体见代码。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define int unsigned int
typedef long long ll;
const int max_n = 1e5+100;
struct segment{
unsigned int sum[max_n<<2][8];
unsigned int add[max_n<<2][8];
unsigned int ls(int x){return x<<1;}
unsigned int rs(int x){return x<<1|1;}
void f(int id,int l,int r,int val,int tar){
sum[id][tar]+=val*(r-l+1);
if (tar==1){
sum[id][4]+=val*sum[id][2];
sum[id][5]+=val*sum[id][3];
sum[id][7]+=val*sum[id][6];
}
else if (tar==2){
sum[id][4]+=val*sum[id][1];
sum[id][6]+=val*sum[id][3];
sum[id][7]+=val*sum[id][5];
}
else{
sum[id][5]+=val*sum[id][1];
sum[id][6]+=val*sum[id][2];
sum[id][7]+=val*sum[id][4];
}
add[id][tar]+=val;
}
void push_up(int id){
for (int i=1;i<=7;++i)sum[id][i]=sum[ls(id)][i]+sum[rs(id)][i];
}
void push_down(int id,int l,int r){
int mid = (l+r)>>1;
for (int tar=1;tar<=3;++tar){
if (add[id][tar]!=0){
f(ls(id),l,mid,add[id][tar],tar);
f(rs(id),mid+1,r,add[id][tar],tar);
add[id][tar]=0;
}
}
}
void update(int id,int l,int r,int lpos,int rpos,int val,int tar){
if (l>=lpos&&r<=rpos){
f(id,l,r,val,tar);
return;
}
push_down(id,l,r);
int mid = (l+r)>>1;
if (mid>=lpos)update(ls(id),l,mid,lpos,rpos,val,tar);
if (mid+1<=rpos)update(rs(id),mid+1,r,lpos,rpos,val,tar);
push_up(id);
}
}seg;
int n;
int a[4][max_n];
vector<int> st1[4],st2[4];
signed main(){
ios::sync_with_stdio(0);
cin>>n;
int ans=0;
for (int j=1;j<=3;++j){
for (int i=1;i<=n;++i){
cin>>a[j][i];
}
}
for (int i=1;i<=n;++i){
for (int k=1;k<=3;++k){
while (!st1[k].empty()&&a[k][st1[k].back()]<=a[k][i]){
if (st1[k].size()==1)seg.update(1,1,n,1,st1[k].back(),-a[k][st1[k].back()],k);
else seg.update(1,1,n,st1[k][st1[k].size()-2]+1,st1[k].back(),-a[k][st1[k].back()],k);
st1[k].pop_back();
}
if (st1[k].empty())seg.update(1,1,n,1,i,a[k][i],k);
else seg.update(1,1,n,st1[k].back()+1,i,a[k][i],k);
st1[k].push_back(i);
while (!st2[k].empty()&&a[k][st2[k].back()]>=a[k][i]){
if (st2[k].size()==1)seg.update(1,1,n,1,st2[k].back(),a[k][st2[k].back()],k);
else seg.update(1,1,n,st2[k][st2[k].size()-2]+1,st2[k].back(),a[k][st2[k].back()],k);
st2[k].pop_back();
}
if (st2[k].empty())seg.update(1,1,n,1,i,-a[k][i],k);
else seg.update(1,1,n,st2[k].back()+1,i,-a[k][i],k);
st2[k].push_back(i);
}
ans+=seg.sum[1][7];
}cout<<ans<<endl;
}
京公网安备 11010502036488号