线段树
线段树是我的弱项
我们来看这一题:
要维护值得乘积
对 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; }