二打可持久化线段树感想

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

下面我放一个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("%lldn",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("%lldn",query(rot[a-1],rot[b],c)-Max);
    }
    return 0;
}

By njc

原文链接: https://www.cnblogs.com/mudrobot/p/13329097.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    二打可持久化线段树感想

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/367763

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午5:57
下一篇 2023年3月2日 下午5:58

相关推荐