hdu4578线段树维护平方和,立方和(加,乘,赋值)或者珂朵莉树

Posted json-five

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu4578线段树维护平方和,立方和(加,乘,赋值)或者珂朵莉树相关的知识,希望对你有一定的参考价值。

一开始我用线段树去做,结果debug了一个下午和晚上QAQ,后来学了珂朵莉树,发现这题原来可以这么简单的写,发出两个代码对比一下

#include<bits/stdc++.h>
#define ll  unsigned long long
using namespace std;
const ll INFINITE = INT_MAX;
const ll MAXNUM = 100005*4;
ll mod=10007;
struct SegTreeNode
{
    ll p1,p2,p3;
    ll l,r;
    ll addMark;//加数标记
    ll mulMark;//乘数标记
    ll assignMark;//赋值标记
} segTree[MAXNUM];
 
void pushup(ll root)
{
    segTree[root].p1 = (segTree[root*2].p1 + segTree[root*2+1].p1)%mod;
    segTree[root].p2 = (segTree[root*2].p2 + segTree[root*2+1].p2)%mod;
    segTree[root].p3 = (segTree[root*2].p3 + segTree[root*2+1].p3)%mod;
}
 
void build(ll root, ll arr[], ll L, ll R)
{
    segTree[root].addMark = 0;
    segTree[root].mulMark = 1;
    segTree[root].assignMark = 0;
    segTree[root].l=L;
    segTree[root].r=R;
    if(L == R)//叶子节点
    {
        segTree[root].p1 = segTree[root].p2=segTree[root].p3=0;
    }
    else
    {
        ll mid = (L + R) / 2;
        build(root*2, arr, L, mid);
        build(root*2+1, arr, mid+1, R);
        pushup(root);
    }
}
 
void pushDown(ll root)
{
    SegTreeNode &rt=segTree[root];
    SegTreeNode &lson=segTree[root*2];
    SegTreeNode &rson=segTree[root*2+1];
    ll len1=(lson.r-lson.l+1)%mod;
    ll len2=(rson.r-rson.l+1)%mod;
    if(rt.assignMark)
    {
        rt.assignMark%=mod;
        lson.assignMark =rson.assignMark= rt.assignMark%mod;
        lson.addMark=rson.addMark=0;
        lson.mulMark=rson.mulMark=1;
        lson.p1=(len1*rt.assignMark)%mod;
        lson.p2=((len1*rt.assignMark)%mod*rt.assignMark)%mod;
        lson.p3=(((len1*rt.assignMark)%mod*rt.assignMark)%mod*rt.assignMark)%mod;
        rson.p1=(len2*rt.assignMark)%mod;
        rson.p2=((len2*rt.assignMark)%mod*rt.assignMark)%mod;
        rson.p3=(((len2*rt.assignMark)%mod*rt.assignMark)%mod*rt.assignMark)%mod;
        rt.assignMark = 0;
    }
    if(rt.mulMark != 1)
    {
        rt.mulMark%=mod;
        lson.mulMark = (lson.mulMark*rt.mulMark)%mod;
        rson.mulMark = (rson.mulMark*rt.mulMark)%mod;
        if(lson.addMark)lson.addMark=(lson.addMark*rt.mulMark)%mod;
         if(rson.addMark)rson.addMark=(rson.addMark*rt.mulMark)%mod;
        lson.p1=(lson.p1*rt.mulMark)%mod;
        lson.p2=((lson.p2*rt.mulMark)%mod*rt.mulMark)%mod;
        lson.p3=(lson.p3*(((rt.mulMark*rt.mulMark)%mod*rt.mulMark)%mod))%mod;
        rson.p1=(rson.p1*rt.mulMark)%mod;
        rson.p2=((rson.p2*rt.mulMark)%mod*rt.mulMark)%mod;
        rson.p3=(rson.p3*(((rt.mulMark*rt.mulMark)%mod*rt.mulMark)%mod))%mod;
        rt.mulMark = 1;
    }
    if(rt.addMark)
    {
        rt.addMark%=mod;
        lson.addMark = (lson.addMark+rt.addMark)%mod;
        rson.addMark = (rson.addMark+rt.addMark)%mod;
        lson.p3 = ((lson.p3+(((len1*rt.addMark)%mod*rt.addMark)%mod*rt.addMark)%mod)%mod+(((3*rt.addMark)%mod)*(((lson.p1*rt.addMark)%mod+lson.p2)%mod))%mod)%mod;
        lson.p2 = ((lson.p2+ ((len1*rt.addMark)%mod*rt.addMark)%mod)%mod+((2*rt.addMark)%mod*lson.p1)%mod)%mod;
        lson.p1 =( lson.p1+ (len1*rt.addMark)%mod)%mod;
        rson.p3 = ((rson.p3+(((len2*rt.addMark)%mod*rt.addMark)%mod*rt.addMark)%mod)%mod+(((3*rt.addMark)%mod)*(((rson.p1*rt.addMark)%mod+rson.p2)%mod))%mod)%mod;
        rson.p2 = ((rson.p2+ ((len2*rt.addMark)%mod*rt.addMark)%mod)%mod+((2*rt.addMark)%mod*rson.p1)%mod)%mod;
        rson.p1 =(rson.p1+ (len2*rt.addMark)%mod)%mod;
        rt.addMark = 0;
    }
}
 
ll query(ll rt,ll L, ll R,ll p)
{
    if(L == segTree[rt].l&& segTree[rt].r==R)
    {
        if(p==1)return segTree[rt].p1%mod;
        if(p==2)return segTree[rt].p2%mod;
        if(p==3)return segTree[rt].p3%mod;
    }
    pushDown(rt); //----延迟标志域向下传递
    ll mid = (segTree[rt].l+segTree[rt].r)/2;
    if(R <= mid) return query(rt*2,L, R,p);
    else if(L > mid)  return query(rt*2+1,L, R,p);
    else return (query(rt*2,L,mid,p)+query(rt*2+1,mid+1, R,p))%mod;
}
 
void update(ll rt, ll L, ll R, ll c,ll p)
{
    if(L == segTree[rt].l&& segTree[rt].r==R)
    {
        SegTreeNode &root=segTree[rt];
        SegTreeNode &lson=segTree[rt*2];
        SegTreeNode &rson=segTree[rt*2+1];
        ll len=(root.r-root.l+1)%mod;
        if(p==1)
        {
            root.addMark = (root.addMark+c)%mod;
            root.p3 =((root.p3+(((len*c)%mod*c)%mod*c)%mod)%mod+(((3*c)%mod)*(((root.p1*c)%mod+root.p2)%mod))%mod)%mod;
            root.p2 =((root.p2+((len*c)%mod*c)%mod)%mod+((2*root.p1)%mod*c)%mod)%mod;
            root.p1 =(root.p1+ (len*c)%mod)%mod;
        }
        else if(p==2)
        {
            root.mulMark = (root.mulMark*c)%mod;
            if(root.addMark)root.addMark=(root.addMark*c)%mod;
            root.p1 = (root.p1*c)%mod;
            root.p2 = ((root.p2*c)%mod*c)%mod;
            root.p3 = (((root.p3*c)%mod*c)%mod*c)%mod;
        }
        else if(p==3)
        {
            root.addMark = 0;
            root.mulMark = 1;
            root.assignMark=c;
            root.p1 = (len*c)%mod;
            root.p2 = ((len*c)%mod*c)%mod;
            root.p3 = (((len*c)%mod*c)%mod*c)%mod;
        }
        return ;
    }
    pushDown(rt); //延迟标记向下传递
    ll mid = (segTree[rt].l+segTree[rt].r)/2;
    if(R <= mid) update(rt*2,L, R, c,p);
    else if(L > mid)  update(rt*2+1,L, R, c,p);
    else update(rt<<1, L, mid, c, p),update(rt*2+1,mid+1, R, c,p);
    pushup(rt);
}
int main()
{
    ll n,m;
    while(scanf("%llu%llu",&n,&m)&&n+m)
    {
        build(1,NULL,1,n);
        while(m--)
        {
            ll op,x,y,p;
            scanf("%llu%llu%llu%llu",&op,&x,&y,&p);
            if(op==4)
            {
                ll ans=query(1,x,y,p);
                printf("%llu
",ans);
            }
            else
                update(1,x,y,p,op);
        }
    }
    return 0;
}

下面是用珂朵莉树的写法:

#include<bits/stdc++.h>
#define ll long long
#define IT set<node>::iterator
#define I_like_Chtholly_forever 10007
using namespace std;
struct node
{
    ll l,r;
    mutable ll val;
    node(ll L,ll R=-1,ll V=0): l(L), r(R), val(V) {}
    bool operator < (const node& tt)const
    {
        return l<tt.l;   //以区间左端点排序
    }
};
set<node> st;

IT split(ll pos)
{
    IT it=st.lower_bound(node(pos));//二分找到第一个左端点不小于pos的区间
    if(it!=st.end()&&it->l==pos) return it;//pos本身就是某个区间的左端点,不用分裂
    --it;//否则上一个区间才是包含pos的区间
    ll l=it->l,r=it->r,val=it->val;
    st.erase(it);//删除原结点
    st.insert(node(l,pos-1,val));
    return st.insert(node(pos,r,val)).first;//这里.first返回的是迭代器
}
void assign_val(ll l,ll r,ll val)
{
    IT itr=split(r+1),itl=split(l);
    st.erase(itl,itr);
    st.insert(node(l,r,val));
}
void add(ll l,ll r,ll val)
{
    IT itr=split(r+1),itl=split(l);
    for(; itl!=itr; ++itl)
    {
         itl->val=(itl->val+val)%I_like_Chtholly_forever;
    }
}
void mul(ll l,ll r,ll val)
{
    IT itr=split(r+1),itl=split(l);
    for(; itl!=itr; ++itl)
    {
        itl->val=(itl->val*val)%I_like_Chtholly_forever;
    }
}
ll quick_pow(ll a, ll b, ll mod)
{
    ll res = 1;
    ll ans = a % mod;
    while (b)
    {
        if (b&1)
            res = res * ans % mod;
        ans = ans * ans % mod;
        b>>=1;
    }
    return res;
}
ll sum(ll l,ll r,ll en,ll mod)
{
    IT itr=split(r+1),itl=split(l);
    ll res=0;
    for(; itl!=itr; ++itl)
    {
        res = (res + (itl->r-itl->l +1) * quick_pow(itl->val,en,mod))%mod;
    }
    return res;
}
ll a[100005];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n,m;
    while(cin>>n>>m&&n&&m)
    {
        st.clear();
        int op,x,y,c;
        for (int i=1; i<=n; i++ )
        {
            st.insert(node(i,i,0));
        }
        for (int i=0; i<m; i++ )
        {
            cin>>op>>x>>y>>c;
            if(op==1)
            {
                add(x,y,c);
            }
            if(op==2)
            {
                mul(x,y,c);
            }
            if(op==3)
            {
                assign_val(x,y,c);
            }
            if(op==4)
            {
                cout<<sum(x,y,c,I_like_Chtholly_forever)<<endl;
            }
        }
    }
    return 0;
}

可以明显看出珂朵莉树在解决这类问题时候写起来会更简单,但是毕竟是玄学算法,且用且珍惜

以上是关于hdu4578线段树维护平方和,立方和(加,乘,赋值)或者珂朵莉树的主要内容,如果未能解决你的问题,请参考以下文章

HDU 4578(线段树

K - Transformation HDU - 4578 线段树经典题(好题)

hdu 4578 Transformation 线段树

hdu4578 (多标记线段树)

Transformation HDU - 4578 完全平方公式和立方公式展开,有点麻烦

[HDOJ4578]Transformation(线段树,多延迟标记)