CF484E Sign on Fence (可持久化线段树+二分答案+区间合并)
题意:
给定一个长度为n的序列a[i]。给定m次询问。
每次查询为l,r,w,表示在区间l,r中,问对于连续的长为w的一段中最小的数字的最大值是多少。
题解:
先把所有元素按高度从大到小排序,以高度为时间轴,元素编号为下标建立可持久化线段树。
那么,第i棵线段树只会保存高度大于等于i的元素下标情况。
对于每个询问,二分答案,在当前二分答案的线段树中找区间l r内最长的连续线段,这里涉及区间合并,是之前从来没有接触过的知识点。
这道题无论是建树方法还是线段树信息的维护都是从没接触过的,需要好好复习。
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+100; const int M=maxn*40; int a[maxn],n,q,T[maxn]; int tot=1; vector<pair<int,int> > z; struct node { int l,r; int len,maxLen,pre,suf; //len表示每个节点代表的区间长度 //maxLen表示每个节点内部最长的连续区间的长度 //pre表示每个节点代表的区间的最大前缀 //suf表示每个节点代表的区间的最大后缀 }segTree[M];//可持久化线段树结构体 bool cmp (pair<int,int> x,pair<int,int> y) { return x.first>y.first;//先按高度从大到小排序 } void push_up (int i) { if (segTree[segTree[i].l].len==segTree[segTree[i].l].pre) { segTree[i].pre=segTree[segTree[i].l].len+segTree[segTree[i].r].pre; } else { segTree[i].pre=segTree[segTree[i].l].pre; } if (segTree[segTree[i].r].len==segTree[segTree[i].r].suf) { segTree[i].suf=segTree[segTree[i].r].len+segTree[segTree[i].l].suf; } else { segTree[i].suf=segTree[segTree[i].r].suf; } segTree[i].maxLen=max(segTree[i].pre,segTree[i].suf); segTree[i].maxLen=max(segTree[i].maxLen,segTree[segTree[i].l].suf+segTree[segTree[i].r].pre); segTree[i].maxLen=max(segTree[i].maxLen,max(segTree[segTree[i].l].maxLen,segTree[segTree[i].r].maxLen)); } void up (int &root,int lst,int l,int r,int p) { root=tot++; segTree[root]=segTree[lst]; segTree[root].len=r-l+1; segTree[lst].len=r-l+1; if (l==r) { segTree[root].maxLen=1; segTree[root].pre=segTree[root].suf=1; return; } int mid=(l+r)>>1; if (p<=mid) up(segTree[root].l,segTree[lst].l,l,mid,p); else up(segTree[root].r,segTree[lst].r,mid+1,r,p); push_up(root); } node merge (node x,node y) { node ans; if (x.len==0) return y; if (x.len==x.pre) { ans.pre=x.len+y.pre; } else { ans.pre=x.pre; } if (y.suf==y.len) { ans.suf=y.len+x.suf; } else { ans.suf=y.suf; } ans.len=x.len+y.len; ans.maxLen=max(ans.suf,ans.pre); ans.maxLen=max(ans.maxLen,x.suf+y.pre); ans.maxLen=max(ans.maxLen,max(x.maxLen,y.maxLen)); return ans; } node query (int root,int l,int r,int L,int R) { if (l>=L&&r<=R) { return segTree[root]; } node ans; ans.l=ans.len=ans.pre=ans.suf=ans.r=ans.maxLen=0; int mid=(l+r)>>1; if (L<=mid) ans=merge(ans,query(segTree[root].l,l,mid,L,R)); if (R>mid) ans=merge(ans,query(segTree[root].r,mid+1,r,L,R)); return ans; } int main () { scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",a+i); z.push_back(make_pair(a[i],i)); } sort(z.begin(),z.end(),cmp); for (int i=0;i<n;i++) up(T[i+1],T[i],1,n,z[i].second);//以高度为轴,编号为下标建立线段树 scanf("%d",&q); while (q--) { int ql,qr,w; scanf("%d%d%d",&ql,&qr,&w); int l=1,r=n,ans=0; while (l<=r) { int mid=(l+r)>>1; if (query(T[mid],1,n,ql,qr).maxLen>=w) { ans=mid; r=mid-1; } else { l=mid+1; } } //printf("%d\n",ans); printf("%d\n",z[ans-1].first); } }