A1517. 动态树 树链剖分+线段树

本文详细介绍了如何使用树链分解结合线段树进行高效查询与更新操作,适用于解决复杂树形结构的问题。通过标记技术简化状态转移,实现快速的路径查找与更新,特别适用于竞赛编程和算法优化场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

打个标记就能求出树链的并了。。

#include<iostream>
#include<cstdio>
using namespace std;

const int N=200005;
const int base=2147483647;
int head[N],next[N<<1],list[N<<1],fa[N],deep[N],belong[N],size[N],in[N],out[N];
int l[N<<2],r[N<<2],sum[N<<2],ans[N<<2],tag1[N<<2],tag2[N<<2];
int n,m,cnt,dfn;

inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}

inline void insert(int x,int y)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
}

void dfs1(int x)
{
    size[x]=1;
    for (int i=head[x];i;i=next[i])
        if (list[i]!=fa[x])
        {
            fa[list[i]]=x;
            deep[list[i]]=deep[x]+1;
            dfs1(list[i]);
            size[x]+=size[list[i]];
        }
}

void dfs2(int x,int chain)
{
    in[x]=++dfn; belong[x]=chain;
    int k=0;
    for (int i=head[x];i;i=next[i])
        if (list[i]!=fa[x]&&size[list[i]]>size[k])
            k=list[i];
    if (!k) {out[x]=dfn; return;}
    dfs2(k,chain);
    for (int i=head[x];i;i=next[i])
        if (list[i]!=fa[x]&&list[i]!=k)
            dfs2(list[i],list[i]);
    out[x]=dfn;
}   

inline void pushup(int k)
{
    sum[k]=sum[k<<1]+sum[k<<1|1];
    ans[k]=ans[k<<1]+ans[k<<1|1];
}

inline void pushdown(int k)
{
    if (l[k]==r[k]) return;
    if (tag1[k])
    {
        tag1[k<<1]+=tag1[k];
        tag1[k<<1|1]+=tag1[k];
        sum[k<<1]+=(r[k<<1]-l[k<<1]+1)*tag1[k];
        sum[k<<1|1]+=(r[k<<1|1]-l[k<<1|1]+1)*tag1[k];
        tag1[k]=0;
    }
    if (tag2[k]!=-1)
    {
        tag2[k<<1]=tag2[k<<1|1]=tag2[k];
        ans[k<<1]=tag2[k]*sum[k<<1];
        ans[k<<1|1]=tag2[k]*sum[k<<1|1];
        tag2[k]=-1;
    }
}

void build(int k,int x,int y)
{
    l[k]=x; r[k]=y; tag2[k]=-1;
    if (l[k]==r[k]) return;
    int mid=l[k]+r[k]>>1;
    build(k<<1,x,mid); build(k<<1|1,mid+1,y);
    pushup(k);
}

void add(int k,int x,int y,int val)
{
    if (l[k]==x&&r[k]==y)
    {
        tag1[k]+=val;
        sum[k]+=(r[k]-l[k]+1)*val;
        return;
    }
    pushdown(k);
    int mid=l[k]+r[k]>>1;
    if (y<=mid) add(k<<1,x,y,val);
    else if (x>mid) add(k<<1|1,x,y,val);
    else add(k<<1,x,mid,val),add(k<<1|1,mid+1,y,val);
    pushup(k);
}

void modify(int k,int x,int y,int val)
{
    if (tag2[k]==val) return;
    if (l[k]==x&&r[k]==y)
    {
        tag2[k]=val;
        ans[k]=sum[k]*val;
        return;
    }
    pushdown(k);
    int mid=l[k]+r[k]>>1;
    if (y<=mid) modify(k<<1,x,y,val);
    else if (x>mid) modify(k<<1|1,x,y,val);
    else modify(k<<1,x,mid,val),modify(k<<1|1,mid+1,y,val);
    pushup(k);
}

inline void solve(int x,int f,int val)
{
    while (belong[x]!=belong[f])
    {
        modify(1,in[belong[x]],in[x],val);
        x=fa[belong[x]];
    }
    modify(1,in[f],in[x],val);
}

int main()
{
    n=read();
    for (int i=1;i<n;i++)
    {
        int u=read(),v=read();
        insert(u,v); insert(v,u);
    }
    dfs1(1); dfs2(1,1); build(1,1,n);
    m=read();
    while (m--)
    {
        int opt=read();
        if (!opt)
        {
            int x=read(),y=read();
            add(1,in[x],out[x],y);
        }
        else
        {
            int k=read();
            for (int i=1;i<=k;i++)
            {
                int u=read(),v=read();
                if (deep[u]<deep[v]) swap(u,v);
                solve(u,v,1);
            }
            printf("%d\n",ans[1]&base);
            modify(1,1,n,0);
        }
    }
    return 0;
}           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值