树链刨分 线段树 区间开方 区间求和

HDU 4027

线段树区间开方、区间求和

不过这个好像有点问题,就是在update那个函数里,有一个小的剪枝,就是当 t[p].sum==t[p].r-t[p].l+1 时,直接return,我感觉这里是错的,因为如果这个区间里有一个值为0,还有一个值为2,其他值全是0,这个地方就不能这样了。如果题目保证输入点权都是大于0的就可以了,但题目并没有保证。如果不加这个剪枝的话会T,加上的话应该会WA,但是AC了,应该是因为题目后面没有点权为0的数据吧......

ACcode:

#include<bits/stdc++.h>
#define de cout<<endl<<endl<<endl
typedef long long ll;
const ll N=2e5+10;
using namespace std;
ll n,q,r;
ll a[N<<2];
ll tot,ver[N<<1],Next[N<<1],head[N<<1];

void add(ll x,ll y)
{
    ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
}

//以下是线段树******************************************************************
struct stree
{
    ll l,r;
    ll sum,add;
} t[N<<2];
void build(ll p,ll l,ll r)   //建树 build(1,1,n)
{
    t[p].l=l,t[p].r=r;
    if(l==r)
    {
        t[p].sum=a[l];
        return ;
    }
    ll mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p].sum=t[p*2].sum+t[p*2+1].sum;
}

void update(ll p,ll l,ll r)
{
    if(t[p].sum==t[p].r-t[p].l+1)
        return ;
    //上面这一句有点小问题,比如当这个区间的点权为 0 2 1 1 1 1 ......
    if(t[p].l==t[p].r)
    {
        t[p].sum=sqrt(t[p].sum);
        return ;
    }
    ll  mid=(t[p].l+t[p].r)>>1;
    if(l<=mid)  update(p*2,l,r);
    if(r>mid) update(p*2+1,l,r);
    t[p].sum=t[p*2].sum+t[p*2+1].sum;
}

//第l到r个数的和,调用入口:query(1,l,r)
ll query(ll p,ll l,ll r)
{
    if(l<=t[p].l&&r>=t[p].r)
        return t[p].sum;
    ll mid=(t[p].l+t[p].r)/2;
    ll val=0;
    if(l<=mid)
        val=val+query(p*2,l,r);
    if(r>mid)
        val=val+query(p*2+1,l,r);
    return val;
}
//以上是线段树*********************************************************************

int main()
{
    ll TT=0;
    while(scanf("%lld",&n)!=EOF)
    {
        tot=0;
        r=1;
        for(ll i=1;i<=n;i++)   scanf("%lld",&a[i]);
        build(1,1,n);
        ll ans;
        scanf("%lld",&q);
        printf("Case #%lld:\n",++TT);
        while(q--)
        {
            ll op,x,y;
            scanf("%lld%lld%lld",&op,&x,&y);
            if(x>y)
                swap(x,y);
            if(op==0)
                update(1,x,y);
            else
            {
                ans=query(1,x,y);
                printf("%lld\n",ans);
            }
        }
        printf("\n");
    }
    return 0;
}

HDU 6547 

树链刨分+线段树区间开方区间求和

ACcode:

#include<bits/stdc++.h>
#define de cout<<endl<<endl<<endl
typedef long long ll;
const ll N=2e5+10;
using namespace std;
ll n,q,r;
ll a[N<<2],b[N<<2];
ll tot,ver[N<<1],Next[N<<1],head[N<<1];
ll dep[N],fa[N],Size[N],son[N];
ll cnt,id[N],top[N];
/*
b[i]    初始节点的权值
a[i]    新建节点的权值
题目输入的是b[i],线段树中用的是a[i]

dep[i]  该节点的深度
fa[i]   该节点的父亲
Size[i] 该非叶子节点的子树大小
son[i]  i的重儿子

cnt     新建节点时用来存编号的
id[i]   该节点的新编号
top[i]  该节点所在链的顶端节点编号
*/
void add(ll x,ll y)
{
    ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
}
void dfs1(ll x,ll f,ll deep) //当前节点   父亲    深度
{
    dep[x]=deep;
    fa[x]=f;
    Size[x]=1;
    ll maxson=-1;
    for(ll i=head[x];i;i=Next[i])
    {
        ll y=ver[i];
        if(y==f)    continue;
        dfs1(y,x,deep+1);
        Size[x]+=Size[y];
        if(Size[y]>maxson)
            son[x]=y,maxson=Size[y];
    }
}
void dfs2(ll x,ll topf)    //当前节点  当前链的最顶端的节点
{
    id[x]=++cnt;
    a[cnt]=b[x];
    top[x]=topf;
    if(son[x]==0)   return ;
    dfs2(son[x],topf);
    for(ll i=head[x];i;i=Next[i])
    {
        ll y=ver[i];
        if(y==fa[x]||y==son[x]) continue;
        dfs2(y,y);
    }
}

//以下是线段树******************************************************************
struct stree
{
    ll l,r;
    ll sum,add;
} t[N<<2];
void build(ll p,ll l,ll r)   //建树 build(1,1,n)
{
    t[p].l=l,t[p].r=r;
    if(l==r)
    {
        t[p].sum=a[l];
        return ;
    }
    ll mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p].sum=t[p*2].sum+t[p*2+1].sum;
}

void update(ll p,ll l,ll r)
{
    if(t[p].l==t[p].r)
    {
        t[p].sum=sqrt(t[p].sum);
        return ;
    }
    ll  mid=(t[p].l+t[p].r)>>1;
    if(l<=mid)  update(p*2,l,r);
    if(r>mid) update(p*2+1,l,r);
    t[p].sum=t[p*2].sum+t[p*2+1].sum;
}

//第l到r个数的和,调用入口:query(1,l,r)
ll query(ll p,ll l,ll r)
{
    if(l<=t[p].l&&r>=t[p].r)
        return t[p].sum;
    //spread(p);
    ll mid=(t[p].l+t[p].r)/2;
    ll val=0;
    if(l<=mid)
        val=val+query(p*2,l,r);
    if(r>mid)
        val=val+query(p*2+1,l,r);
    return val;
}
//以上是线段树*********************************************************************

void update1(ll x,ll y) //给节点x到节点y这条链上的所有节点都加上z
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,id[top[x]],id[x]);

        x=fa[top[x]];
    }
    if(dep[x]>dep[y])   swap(x,y);
    update(1,id[x],id[y]);
}

ll query1(ll x,ll y) //询问节点x到节点y这条链上的所有节点的和
{
    ll ret=0,res;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        res=query(1,id[top[x]],id[x]);
        ret+=res;
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])   swap(x,y);
    ret+=query(1,id[x],id[y]);
    return ret;
}
int main()
{
    tot=0;
    cnt=0;
    memset(a,0,sizeof a);
    scanf("%lld%lld",&n,&q);
    r=1;
    for(ll i=1;i<=n;i++)   scanf("%lld",&b[i]);
    ll x,y;
    for(ll i=1;i<=n-1;i++)
        {scanf("%lld%lld",&x,&y);add(x,y);add(y,x);}
    dfs1(r,0,1);
    dfs2(r,r);
    build(1,1,n);
    ll ans;
    while(q--)
    {
        ll op,x,y;
        scanf("%lld%lld%lld",&op,&x,&y);
        if(op==0)
            update1(x,y);
        else
        {
            ans=query1(x,y);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值