bzoj 3685

线段树

方法一:

值域线段树,递归去写的,每次节点存出现次数.

对于几个操作, 1,2 直接加减就好 ; 3,4 操作贪心往某一个方向找 .7也很简单,主要说前驱后继怎么找。我是先找这个数第几小,根据相应关系得出我们需要输出第几小。然后就写了一下 TLE。详见代码一;

解决办法

加入输入外挂 .... 过了.详见代码二。

方法二:

参考了zkw,原来就是递归改为循环,再用到满二叉树性质.有些能够O(1) 求出.

具体做法:先确定范围,让二叉树最后一层节点数>=n.并找到最后一层节点编号 L-R .和前面有sz个节点. 增删我们从 sz+x这个节点开始加上一个数,之后除以2.
再写一个查询最大最小.那个函数传入的是节点编号.所以他可以查询某个子树的max,min.结合到前驱后继。比如查询x前驱,我就从x那个最底层点开始,看我是右儿子?如果是,看左儿子节点有数?有查询那颗子树的max,即为答案,反之也是一样的。最后一个操作直接来。sz+x。对于下标处理原题 [0,n-1] . 线段树 是1开始所以减一莫要忘记.
具体写法,参考代码三。

//代码一
#include <stdio.h>



const int maxn=1e6+10;


int T[maxn*4];
void ins(int i,int l,int r,int x,int val)// 1 2
{
    if(l==r) 
    {
        T[i]=val;
        return ;
    }
    int mid=(l+r)>>1;
    if(x<=mid) ins(i<<1,l,mid,x,val);
    else ins(i<<1|1,mid+1,r,x,val);
    T[i]=T[i<<1]+T[i<<1|1];
}
int fmax(int i,int l,int r)
{
    if(T[i]==0) return -1;
    if(l==r) return l;
    int mid=(l+r)>>1;
    if(T[i<<1|1]) return fmax(i<<1|1,mid+1,r);
    else return fmax(i<<1,l,mid);
}
int fmin(int i,int l,int r)
{
    if(T[i]==0) return -1;
    if(l==r) return l;
    int mid=(l+r)>>1;
    if(T[i<<1]) return fmin(i<<1,l,mid);
    else return fmin(i<<1|1,mid+1,r);
}


int fx(int i,int l,int r,int x)
{
    if(l==r) return T[i]?1:-1;
    int mid=(l+r)>>1;
    if(x<=mid) return fx(i<<1,l,mid,x);
    else return fx(i<<1|1,mid+1,r,x);
}



bool flag;
int kth(int i,int l,int r,int x)
{
    if(l==r) 
    {
        flag=T[i];
        return T[i];
    }
    int mid=(l+r)>>1;
    if(x<=mid) return kth(i<<1,l,mid,x);
    else return T[i<<1]+kth(i<<1|1,mid+1,r,x); 
}

int fkth(int i,int l,int r,int k)
{
    if(l==r) 
    {
        if(T[i]) return l;
        else return -1;
    }
    int mid=(l+r)>>1;
    int sum=T[i<<1];
    if(sum>=k) return fkth(i<<1,l,mid,k);
    else return fkth(i<<1|1,mid+1,r,k-sum);
}


int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int op,x;
        scanf("%d",&op);
        if(op==3||op==4) ;
        else scanf("%d",&x);


        if(op==1) ins(1,-1,n+1,x,1);
        else if(op==2) ins(1,-1,n+1,x,0);
        else if(op==3) printf("%d
",fmin(1,-1,n+1));
        else if(op==4) printf("%d
",fmax(1,-1,n+1));
        else if(op==5)
        {
            int k=kth(1,-1,n+1,x);
            //printf("k=%d flag=%d
",k,flag?1:0);
            if(flag) k--;
            printf("%d
",fkth(1,-1,n+1,k));
        }
        else if(op==6)
        {
            int k=kth(1,-1,n+1,x);
            k++;
            printf("%d
",fkth(1,-1,n+1,k));
        }
        else printf("%d
",fx(1,-1,n+1,x));
    }
    return 0;
}

/*

10 100
1 2
1 4
1 6
1 8
1 10

*/

//代码二
#include <stdio.h>



const int maxn=1e6+10;
inline char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int sc()
{
    char ch=nc();
    int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}

int T[maxn*4];
void ins(int i,int l,int r,int x,int val)// 1 2
{
    if(l==r) 
    {
        T[i]=val;
        return ;
    }
    int mid=(l+r)>>1;
    if(x<=mid) ins(i<<1,l,mid,x,val);
    else ins(i<<1|1,mid+1,r,x,val);
    T[i]=T[i<<1]+T[i<<1|1];
}
int fmax(int i,int l,int r)
{
    if(T[i]==0) return -1;
    if(l==r) return l;
    int mid=(l+r)>>1;
    if(T[i<<1|1]) return fmax(i<<1|1,mid+1,r);
    else return fmax(i<<1,l,mid);
}
int fmin(int i,int l,int r)
{
    if(T[i]==0) return -1;
    if(l==r) return l;
    int mid=(l+r)>>1;
    if(T[i<<1]) return fmin(i<<1,l,mid);
    else return fmin(i<<1|1,mid+1,r);
}


int fx(int i,int l,int r,int x)
{
    if(l==r) return T[i]?1:-1;
    int mid=(l+r)>>1;
    if(x<=mid) return fx(i<<1,l,mid,x);
    else return fx(i<<1|1,mid+1,r,x);
}



bool flag;
int kth(int i,int l,int r,int x)
{
    if(l==r) 
    {
        flag=T[i];
        return T[i];
    }
    int mid=(l+r)>>1;
    if(x<=mid) return kth(i<<1,l,mid,x);
    else return T[i<<1]+kth(i<<1|1,mid+1,r,x); 
}

int fkth(int i,int l,int r,int k)
{
    if(l==r) 
    {
        if(T[i]) return l;
        else return -1;
    }
    int mid=(l+r)>>1;
    int sum=T[i<<1];
    if(sum>=k) return fkth(i<<1,l,mid,k);
    else return fkth(i<<1|1,mid+1,r,k-sum);
}


int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int op,x;
        op=sc();
        if(op==3||op==4) ;
        else x=sc();


        if(op==1) ins(1,-1,n+1,x,1);
        else if(op==2) ins(1,-1,n+1,x,0);
        else if(op==3) printf("%d
",fmin(1,-1,n+1));
        else if(op==4) printf("%d
",fmax(1,-1,n+1));
        else if(op==5)
        {
            int k=kth(1,-1,n+1,x);
            //printf("k=%d flag=%d
",k,flag?1:0);
            if(flag) k--;
            printf("%d
",fkth(1,-1,n+1,k));
        }
        else if(op==6)
        {
            int k=kth(1,-1,n+1,x);
            k++;
            printf("%d
",fkth(1,-1,n+1,k));
        }
        else printf("%d
",fx(1,-1,n+1,x));
    }
    return 0;
}

/*

10 100
1 2
1 4
1 6
1 8
1 10

*/
//代码三
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
const int maxn=1e6+10;
int T[maxn*4],sz,L,R;
void ins(int i,int val)
{
    i=i+sz;
    if(T[i]==1&&val==1) return ;
    if(T[i]==0&&val==-1) return ;
    for(;i>0;i>>=1) T[i]+=val;
}
int fmax(int i)
{
    if(T[i]==0) return 0;
    while(i<=sz)
    {
        if(T[i<<1|1]) i=i<<1|1;
        else i=i<<1;
    }
    return i-sz;
}
int fmin(int i)
{
    if(T[i]==0) return 0;
    while(i<=sz)
    {
        if(T[i<<1]) i=i<<1;
        else i=i<<1|1;
    }
    return i-sz;
}
int fpre(int i)
{
    i=i+sz;
    for(;i!=1;i>>=1)
        if((i&1)&&T[i^1]) return fmax(i^1);
    return 0;
}
int fsuc(int i)
{
    i=i+sz;
    for(;i!=1;i>>=1)
        if(!(i&1)&&T[i^1]) return fmin(i^1);
    return 0;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    sz=0;
    for(int i=1;i<n;i=(i<<1))
    {
        sz+=i;
        L=sz+1;
        R=sz+(i<<1);
    }
    while(m--)
    {
        int op,x;
        scanf("%d",&op);
        if(op==3||op==4);
        else scanf("%d",&x);
        x++;
        if(op==1) ins(x,1);
        else if(op==2) ins(x,-1);
        else if(op==3) printf("%d
",fmin(1)-1);
        else if(op==4) printf("%d
",fmax(1)-1);
        else if(op==5) printf("%d
",fpre(x)-1);
        else if(op==6) printf("%d
",fsuc(x)-1);
        else printf("%d
",T[sz+x]?1:-1);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/coded-ream/p/7522087.html