博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Greedy Sequence(2019南京icpc网络预选赛)主席树求区间小于k的最大值
阅读量:4137 次
发布时间:2019-05-25

本文共 3718 字,大约阅读时间需要 12 分钟。

题意:给出n个整数,构造s1,s2,s3…sn s1,s2,s3…sns1,s2,s3…sn,si sisi满足五个条件

1、s1[i]=i s1[i]=is1[i]=i
2、对于1<j<=n 对于1<j<=n对于1<j<=n,si[j]<si[j−1] si[j]<si[j-1]si[j]<si[j−1]
3、对于任意的si[j] si[j]si[j]在a串中的位置pos[j] pos[j]pos[j],满足∣pos[j]−pos[j−1]∣<=k |pos[j]-pos[j-1]|<=k∣pos[j]−pos[j−1]∣<=k,且si sisi中的每一个数字只能a aa中出现一次
4、如果选择的si sisi长度小于n nn,其余位置就填0
5、尽量使bi bibi足够大(能得到的最大字典序)
输出每个bi bibi的非0数字的个数。
主席树求区间小于k的最大值。。。卡了好久都没有写出来,结果是函数传参传错了。。
代码如下:

#include
#define ll long long#define inf 0x3f3f3f3fusing namespace std;const int maxx=1e5+100;struct node{
int l; int r; int sum;}p[maxx<<5];int a[maxx],root[maxx],vis[maxx],cnt[maxx];int n,k,tot;inline void pushup(int cur){
p[cur].sum=p[p[cur].l].sum+p[p[cur].r].sum;}inline int build(int l,int r){
int cur=++tot; p[cur].sum=0; if(l==r) return cur; int mid=l+r>>1; p[cur].l=build(l,mid); p[cur].r=build(mid+1,r); return cur;}inline int update(int rot,int pos,int l,int r){
int cur=++tot; p[cur]=p[rot]; if(l==r) {
p[cur].sum++; return cur; } int mid=l+r>>1; if(pos<=mid) p[cur].l=update(p[rot].l,pos,l,mid); else p[cur].r=update(p[rot].r,pos,mid+1,r); pushup(cur); return cur;}inline int query(int pos,int l,int r,int lrot,int rrot){
if(l==r) {
if(p[rrot].sum-p[lrot].sum>0) return l; else return 0; } int mid=l+r>>1; if(pos>mid) {
int ans=0; if(pos>=r) {
if(p[p[rrot].r].sum-p[p[lrot].r].sum>0) ans=max(ans,query(pos,mid+1,r,p[lrot].r,p[rrot].r)); else if(p[p[rrot].l].sum-p[p[lrot].l].sum>0&&ans==0) ans=max(ans,query(pos,l,mid,p[lrot].l,p[rrot].l)); return ans; } if(p[p[rrot].r].sum-p[p[lrot].r].sum>0) ans=max(ans,query(pos,mid+1,r,p[lrot].r,p[rrot].r)); if(ans==0&&p[p[rrot].l].sum-p[p[lrot].l].sum>0) ans=max(ans,query(pos,l,mid,p[lrot].l,p[rrot].l)); return ans; } else {
int ans=0; if(p[p[rrot].l].sum-p[p[lrot].l].sum>0) ans=max(ans,query(pos,l,mid,p[lrot].l,p[rrot].l)); return ans; }}int main(){
int t; scanf("%d",&t); while(t--) {
tot=0; memset(cnt,0,sizeof(cnt)); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]),vis[a[i]]=i; root[0]=build(1,n); for(int i=1;i<=n;i++) root[i]=update(root[i-1],a[i],1,n); cnt[1]=1; for(int i=2;i<=n;i++) {
int num1,num2,num; int pos1=max(vis[i]-k,1),pos2=max(vis[i]-1,1); int pos3=min(vis[i]+1,n),pos4=min(vis[i]+k,n); if(pos1!=pos2) num1=query(i,1,n,root[pos1-1],root[pos2]);else num1=a[pos1]

同样类似的还有一段区间求大于k的最小的。。

线段树做法,各种优势胜过主席树

#include
#define ll long longusing namespace std;const int maxx=1e5+100;struct node{
int l; int r; int sum;}p[maxx<<2];int a[maxx],vis[maxx],cnt[maxx];int n,k;inline void pushup(int cur){
p[cur].sum=max(p[cur<<1].sum,p[cur<<1|1].sum);}inline void build(int l,int r,int cur){
p[cur].l=l; p[cur].r=r; p[cur].sum=0; if(l==r) return ; int mid=l+r>>1; build(l,mid,cur<<1); build(mid+1,r,cur<<1|1);}inline void update(int pos,int cur,int v){
int L=p[cur].l; int R=p[cur].r; if(L==R) {
p[cur].sum=v; return ; } int mid=L+R>>1; if(pos<=mid) update(pos,cur<<1,v); else update(pos,cur<<1|1,v); pushup(cur);}inline int query(int l,int r,int cur){
int L=p[cur].l; int R=p[cur].r; if(l<=L&&R<=r) return p[cur].sum; int mid=L+R>>1; if(r<=mid) return query(l,r,cur<<1); else if(l>mid) return query(l,r,cur<<1|1); else return max(query(l,mid,cur<<1),query(mid+1,r,cur<<1|1));}int main(){
int t; scanf("%d",&t); while(t--) {
memset(cnt,0,sizeof(cnt)); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]),vis[a[i]]=i; build(1,n,1); update(vis[1],1,1);cnt[1]=1; for(int i=2;i<=n;i++) {
int num=query(max(vis[i]-k,1),min(vis[i]+k,n),1); cnt[i]=cnt[num]+1; update(vis[i],1,i); } for(int i=1;i<=n;i++) printf("%d%c",cnt[i],i==n?'\n':' '); }}

努力加油a啊,(o)/~

转载地址:http://xztvi.baihongyu.com/

你可能感兴趣的文章