题意:bc 77div1 d题(中文题面),其实就是询问一个区间有多少不同的三元组,当然这个三元组要符合条件
分析(先奉上官方题解)
首先将数列中所有满足条件的三元组处理出来,数量不会超过 nn个。
设 pre[i] 为第 i 个三元组前一次出现的位置,如果在前面没有出现过则设为0,对于不合法的三元组,pre[i]设为 n。
这样对于一个查询 [L, R], 我们只不需要计算出 在这个区间内有多少个三元组的 pre 值是小于 L 的。
到这里,就可以使用可持久化线段树来计算了。
-------------------------------------------------------------华丽的分割线
然后蒟蒻表示不会这种在线的主席树做法,主席树据说很好,马上去学习
然后介绍本蒟蒻的离线做法,其实都是套路,就是求一个区间包含了,多少个小区间(即三元组)
首先和题解一样,找到符合条件的三元组,记录它的序号id,这个三元组的每个元素,他的右边界
然后按照三元组排序,以及他的id,这样处理每个三元组的pre,即在他左边,与他相同的三元组的id
然后恢复下顺序
然后就是离线的套路,把查询区间按照右端点排序,更新所有三元组右边界小于他的左端点,然后区间求和,就是答案
但是这个题有一个点,要避免查询重复,所以在当前查询的时候,要保证没有重复,所以更新三元组时,要把他的pre删掉(因为相同)
这样对于重复的三元组,只保留最靠近当前查询区间右端的
代码:
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> using namespace std; typedef long long LL; const int N=2e5+5; const int INF=0x3f3f3f3f; struct Node{ int a,b,c,id,pre,r; bool operator==(const Node &rhs)const{ if(a==rhs.a&&b==rhs.b&&c==rhs.c) return 1; return 0; } }o[N]; int n,T,q; bool cmp1(Node x,Node y){ if(x.a!=y.a) return x.a<y.a; if(x.b!=y.b) return x.b<y.b; if(x.c!=y.c) return x.c<y.c; return x.id<y.id; } bool cmp2(Node x,Node y){ return x.id<y.id; } int d[N],ans[N]; struct Q{ int l,r,id; bool operator<(const Q &rhs)const{ return r<rhs.r; } }p[N]; int bit[N]; void add(int x,int t){ for(int i=x;i<=n;i+=i&(-i)) bit[i]+=t; } int get(int x){ int ans=0; for(int i=x;i>0;i-=i&(-i)) ans+=bit[i]; return ans; } int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); int cnt=0; for(int i=1;i<=n;++i){ scanf("%d",&d[i]); if(i<=2)continue; if(d[i]>=d[i-1]&&d[i-1]>=d[i-2]){ ++cnt; o[cnt].a=d[i-2],o[cnt].b=d[i-1]; o[cnt].c=d[i],o[cnt].pre=-1; o[cnt].r=i,o[cnt].id=cnt; } } sort(o+1,o+1+cnt,cmp1); for(int i=2;i<=n;++i){ if(o[i]==o[i-1]){ o[i].pre=o[i-1].id; } } sort(o+1,o+1+cnt,cmp2); scanf("%d",&q); for(int i=1;i<=q;++i){ scanf("%d%d",&p[i].l,&p[i].r); p[i].id=i; } sort(p+1,p+1+q); int pos=1; memset(bit,0,sizeof(bit)); for(int i=1;i<=q;++i){ for(;pos<=cnt&&o[pos].r<=p[i].r;++pos){ int pre=o[pos].pre; if(pre!=-1) add(o[pre].r-2,-1); add(o[pos].r-2,1); } ans[p[i].id]=get(p[i].r)-get(p[i].l-1); } for(int i=1;i<=q;++i) printf("%d ",ans[i]); } return 0; }