zoukankan      html  css  js  c++  java
  • 二打可持久化线段树感想

    昨天突然脑袋比较清醒,好像似乎以前没有搞太懂的可持久化线段树一下子就搞懂了,结果打了几遍还是出现了一些意想不到的问题,下面我就来整理一下,防止以后重蹈覆辙!

    下面我放一个50分的代码:

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    struct sd{
        LL l,r,cnt,son[2];
    }node[1000005];
    const LL Max=1e9+7;
    LL ini[1000004],rot[1000004],n,m,cnt;
    void update(LL k){node[k].cnt=node[node[k].son[0]].cnt+node[node[k].son[1]].cnt;}
    /*void modify(LL k,LL l,LL r,LL pos)
    {
        node[k].l=l;node[k].r=r;LL mid=(l+r)/2;
        if(l==r) node[k].cnt++;
        else if(pos<=mid)
        {
            ++cnt;
            node[cnt]=node[node[k].son[0]];
            node[k].son[0]=cnt;
            modify(node[k].son[0],l,mid,pos);
        }
        else
        {
            ++cnt;
            node[cnt]=node[node[k].son[1]];
            node[k].son[1]=cnt;
            modify(node[k].son[1],mid+1,r,pos);
        }
        update(k);
    }*/
    LL query(LL lroot,LL rroot,LL rank)
    {
        if(node[rroot].l==node[rroot].r) 
        return node[rroot].l;//strange
        else
        {
            LL delta=node[node[rroot].son[0]].cnt-node[node[lroot].son[0]].cnt;
            if(rank<=delta) return query(node[lroot].son[0],node[rroot].son[0],rank);
            else return query(node[lroot].son[1],node[rroot].son[1],rank-delta);
        }
    }
    inline void modify(LL k,long long l,long long r,LL val)
    {
        node[k].l=l;node[k].r=r;
        if(l==r)
        {
            node[k].cnt++;return;
        }
        long long mid=l+r;mid/=2;
        cnt++;
        node[cnt]=node[node[k].son[0]];
        node[k].son[0]=cnt;cnt++;
        node[cnt]=node[node[k].son[1]];
        node[k].son[1]=cnt;
        if(val<=mid)
        {
           
            modify(node[k].son[0],l,mid,val);
        }
        else
        {
           
            
            modify(node[k].son[1],mid+1,r,val);
        }
        update(k);
    }
    
    //LL query(LL rl,LL rr,LL val)
    //{
    //    if(node[rr].l==node[rr].r) return node[rr].l;//very very important
    //    LL delta=node[node[rr].son[0]].cnt-node[node[rl].son[0]].cnt;
    //    if(val<=delta)
    //    return query(node[rl].son[0],node[rr].son[0],val);
    //    else
    //    return query(node[rl].son[1],node[rr].son[1],val-delta);
    //}
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(LL i=1;i<=n;++i) scanf("%lld",&ini[i]);
        //rot[0]=1;//important
        for(LL i=0;i<=n;++i)
        {
            rot[i]=++cnt;node[rot[i]]=node[rot[i-1]];modify(rot[i],0,2*Max,Max+ini[i]);
        }
        LL a,b,c;
        for(LL i=1;i<=m;++i)
        {
            scanf("%lld%lld%lld",&a,&b,&c);
            printf("%lld
    ",query(rot[a-1],rot[b],c)-Max);
        }
        return 0;
    }
    

    我们可以发现后面的几个点是出了问题的其实就是RE,这个原因其实很容易就可以发现,因为我们如果要查一号位置的话,然后我们就会惊讶的发现,我们会query零号根(rot[0])然后我们把0号根定义的是到1号节点,然后就出事了!!!

    所以说这里cnt应该初始化到1,或者直接改为

    rot[0]=++cnt;
    

    然后我确实是发现了这个问题,但是交上去发现还是RE

    这是为什么?

    然后我发现这次RE的原因是数组开小了,至少电脑是这样认为的,但是其实我的数组是开的够大的,是因为我的动态开点modify的时候开点开了很多没有必要的点,所以导致了空间浪费(我本来以为这样开点可以使开出来的树更加的平衡)但是事实上证明我是错的,因为大家可以好好理解一下为什么下面的query中的第一个if语句一定写的是右根而不是左根!!!

    这篇博客对于上面那个query中的小细节有所解释:
    主席树(可持久化线段树)

    然后把这里改了,在这里再注意下这个主席树节点个数要开到10000000(别数了,一千万)然后你就可以AC这道题了,坑点还是很多的!!!

    AC code:

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    struct sd{
        LL l,r,cnt,son[2];
    }node[10000005];
    const LL Max=1e9+7;
    LL ini[1000004],rot[1000004],n,m,cnt;
    void update(LL k){node[k].cnt=node[node[k].son[0]].cnt+node[node[k].son[1]].cnt;}
    void modify(LL k,LL l,LL r,LL pos)
    {
        node[k].l=l;node[k].r=r;LL mid=(l+r)/2;
        if(l==r) node[k].cnt++;
        else 
    	{
    		if(pos<=mid)
        	{
        	    ++cnt;
        	    node[cnt]=node[node[k].son[0]];
        	    node[k].son[0]=cnt;
        	    modify(node[k].son[0],l,mid,pos);
        	}
        	else
        	{
        	    ++cnt;
        	    node[cnt]=node[node[k].son[1]];
        	    node[k].son[1]=cnt;
        	    modify(node[k].son[1],mid+1,r,pos);
        	}
        	update(k);
    	}
    }
    LL query(LL lroot,LL rroot,LL rank)
    {
        if(node[rroot].l==node[rroot].r) 
        return node[rroot].l;//strange
        else
        {
            LL delta=node[node[rroot].son[0]].cnt-node[node[lroot].son[0]].cnt;
            if(rank<=delta) return query(node[lroot].son[0],node[rroot].son[0],rank);
            else return query(node[lroot].son[1],node[rroot].son[1],rank-delta);
        }
    }
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(LL i=1;i<=n;++i) scanf("%lld",&ini[i]);
        rot[0]=++cnt;//important
        for(LL i=1;i<=n;++i)
        {
            rot[i]=++cnt;node[rot[i]]=node[rot[i-1]];modify(rot[i],0,2*Max,Max+ini[i]);
        }
        LL a,b,c;
        for(LL i=1;i<=m;++i)
        {
            scanf("%lld%lld%lld",&a,&b,&c);
            printf("%lld
    ",query(rot[a-1],rot[b],c)-Max);
        }
        return 0;
    }
    

    By njc

  • 相关阅读:
    el-select下拉框选项太多导致卡顿,使用下拉框分页来解决
    vue+elementui前端添加数字千位分割
    Failed to check/redeclare auto-delete queue(s)
    周末啦,做几道面试题放松放松吧!
    idea快捷键
    解决flink运行过程中报错Could not allocate enough slots within timeout of 300000 ms to run the job. Please make sure that the cluster has enough resources.
    用.net平台实现websocket server
    MQTT实战3
    Oracle 查看当前用户下库里所有的表、存储过程、触发器、视图
    idea从svn拉取项目不识别svn
  • 原文地址:https://www.cnblogs.com/mudrobot/p/13329097.html
Copyright © 2011-2022 走看看