HDU6703 主席树+set

其实这道题很简单,只有一个点需要去解决,也就是要去求一个无序区间最接近K并且大于等于的数,我在用主席树解决这个问题的时候,用val记录当前节点区间的数出现了多少次,并且这个区间的左端点应该要大于等于K。我一开始是走一个Logn的路线,也就是不是走左就是走右,但是遇到了一种情况,譬如k==3,1到3这个区间,是2出现了一次,那么我往下走就永远也永远找不到了答案,后面经过点播,发现左右都可以走,当找到第一个根节点就返回,并且能够证明是一个常数Logn的复杂度(如果走了左,那么右一定有答案),这颠覆了我对线段树的认识,感谢!

#include
using namespace std;
const int cap=1e5+7;
int n,m;
int root[cap],a[cap];
struct P_segmentTree
{
    int lnum,rnum,val;
}node[cap*30];
int cur;
void build(int x,int & y,int l,int r,int c)
{
    node[++cur]=node[x];
    node[cur].val++;
    y=cur;
    if(l==r)
    return;
    int mid=l+r>>1;
    if(mid>=c)
    build(node[x].lnum,node[y].lnum,l,mid,c);
    else
    build(node[x].rnum,node[y].rnum,mid+1,r,c);
}
bool flag;
int zz;
void query(int x,int y,int l,int r,int k)
{
    if(flag)
    return;
    if(l==r)
    {
    zz=l;
    flag=1;
    return;
    }
    int ylnum=node[y].lnum,xlnum=node[x].lnum;
    int yrnum=node[y].rnum,xrnum=node[x].rnum;
    int lval=node[ylnum].val-node[xlnum].val;
    int rval=node[yrnum].val-node[xrnum].val;
    int mid=l+r>>1;
    if(lval>0&&mid>=k)
    query(node[x].lnum,node[y].lnum,l,mid,k);
    if(rval>0&&r>=k)
    query(node[x].rnum,node[y].rnum,mid+1,r,k);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(root,0,sizeof root);
        cur=0;
        for(int i=1;i<=n;i++)
        {
        scanf("%d",&a[i]);
        build(root[i-1],root[i],1,n,a[i]);
        }
        set se;
        int lastans=0;
        while(m--)
        {
            int op;
            scanf("%d",&op);
            if(op==1)
            {
                int pos;
                scanf("%d",&pos);
                pos^=lastans;
                se.insert(a[pos]);
            }
            else
            {
                int r,k;
                scanf("%d%d",&r,&k);
                r^=lastans;
                k^=lastans;
                int ans=1e9;
                auto p=se.lower_bound(k);
                if(p!=se.end())
                ans=min(ans,*p);
                flag=0;
                zz=1e9;
                query(root[r],root[n],1,n,k);
                ans=min(ans,zz);
                if(ans==1e9)
                ans=n+1;
                printf("%d\n",ans);
                lastans=ans;
            }
        }
    }
    return 0;
}

你可能感兴趣的:(树)