【洛谷P4315】月下“毛景树”(树链剖分)

这是一道毒瘤题。

首先题目中给的是边权而不是点权,但是我们把边权移到点上就行了

但是要注意,之后我们修改u,v两点之间的路径时,就不要修改他们的lca,以及当要修改单边的时候,把边的编号*2(因为是双向边),然后挑深度大的那个点来修改

重点是区间覆盖tag和区间加tag。首先注意,进行区间覆盖时,一定要清零区间加tag。然后其次,pushdown的时候一定要先覆盖再加

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 100005
using namespace std;
template<class T>
inline void read(T &x)
{
    x=0;
    static char ch=getchar();
    while(ch<'0'||ch>'9')   ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
int n,first[2*N],tot;
struct Edge{int from,to,next,val;}edge[2*N]; 
inline void addedge(int x,int y,int z)
{
    tot++; edge[tot].from=x; edge[tot].to=y; edge[tot].next=first[x]; edge[tot].val=z; first[x]=tot;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int depth[N],size[N],maxson[N],father[N],val[N];
void dfs1(int now,int fa)
{
    depth[now]=depth[fa]+1;
    father[now]=fa;
    size[now]=1;
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(vis==fa) continue;
        dfs1(vis,now);
        val[vis]=edge[u].val;
        size[now]+=size[vis];
        if(size[vis]>size[maxson[now]]) maxson[now]=vis;
    }
}
int top[N],id[N],wnew[N],sign;
void dfs2(int now,int topf)
{
    top[now]=topf;
    id[now]=++sign;
    wnew[sign]=val[now];
    if(maxson[now]) dfs2(maxson[now],topf);
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(vis==maxson[now]||vis==father[now])  continue;
        dfs2(vis,vis);
    }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct Tree{int l,r,maxv,cover,lazy_add;}tree[4*N];
inline void pushup(int now){ tree[now].maxv=max(tree[2*now].maxv,tree[2*now+1].maxv); }
inline void pushdown(int now)
{
    if(tree[now].cover!=-1)
    {
        tree[2*now].lazy_add=tree[2*now+1].lazy_add=0;
        tree[2*now].cover=tree[2*now].maxv=tree[now].cover;
        tree[2*now+1].cover=tree[2*now+1].maxv=tree[now].cover;
        tree[now].cover=-1;
    }
    tree[2*now].maxv+=tree[now].lazy_add;
    tree[2*now+1].maxv+=tree[now].lazy_add;
    tree[2*now].lazy_add+=tree[now].lazy_add;
    tree[2*now+1].lazy_add+=tree[now].lazy_add; 
    tree[now].lazy_add=0;
}
void build(int now,int l,int r)
{
    tree[now].l=l,tree[now].r=r,tree[now].cover=-1,tree[now].lazy_add=0;
    if(l==r) 
    {
        tree[now].maxv=wnew[l];
        return;
    }
    int m=(l+r)>>1;
    build(2*now,l,m);
    build(2*now+1,m+1,r);
    pushup(now);
}
inline void add(int now,int l,int r,int w)
{
    if(l<=tree[now].l&&tree[now].r<=r)
    {
        tree[now].lazy_add+=w;
        tree[now].maxv+=w;
        return;
    }
    pushdown(now);
    int m=(tree[now].l+tree[now].r)>>1;
    if(l<=m) add(2*now,l,r,w);
    if(r>m) add(2*now+1,l,r,w);
    pushup(now);
}
inline void cover(int now,int l,int r,int w)
{
    if(l<=tree[now].l&&tree[now].r<=r)
    {
        tree[now].cover=w;
        tree[now].maxv=w;
        tree[now].lazy_add=0;
        return;
    }
    pushdown(now);
    int m=(tree[now].l+tree[now].r)>>1;
    if(l<=m) cover(2*now,l,r,w);
    if(r>m) cover(2*now+1,l,r,w);
    pushup(now);
}
inline int query(int now,int l,int r)
{
    if(l<=tree[now].l&&tree[now].r<=r) return tree[now].maxv;
    pushdown(now);
    int m=(tree[now].l+tree[now].r)>>1,res=-INF;
    if(l<=m) res=max(res,query(2*now,l,r));
    if(r>m) res=max(res,query(2*now+1,l,r));
    return res;
} 
inline void Tcover(int x,int y,int z)
{
    while(top[x]!=top[y])
    {
        if(depth[top[x]]<depth[top[y]]) swap(x,y);
        cover(1,id[top[x]],id[x],z);
        x=father[top[x]];
    }
    if(depth[x]>depth[y])   swap(x,y);
    cover(1,id[x]+1,id[y],z);   //lca不能被更新! 
}
inline void Tadd(int x,int y,int z)
{
    while(top[x]!=top[y])
    {
        if(depth[top[x]]<depth[top[y]]) swap(x,y);
        add(1,id[top[x]],id[x],z);
        x=father[top[x]];
    }
    if(depth[x]>depth[y])   swap(x,y);
    add(1,id[x]+1,id[y],z); 
}
inline int Qmax(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(depth[top[x]]<depth[top[y]]) swap(x,y);
        ans=max(ans,query(1,id[top[x]],id[x]));
        x=father[top[x]];
    }
    if(depth[x]>depth[y])   swap(x,y);
    return max(ans,query(1,id[x]+1,id[y]));
}
int main()
{
    read(n);
    for(int i=1,u,v,w;i<=n-1;i++)
    {
        read(u),read(v),read(w);
        addedge(u,v,w); addedge(v,u,w);
    }
    dfs1(1,0);  dfs2(1,1); build(1,1,n);
    string s;
    while(cin>>s)
    {
        int u,v,w; 
        if(s=="Stop")   return 0;
        if(s=="Max")
        {
            read(u),read(v);
            cout<<Qmax(u,v)<<'\n';
        }
        if(s=="Change") //单点修改 
        {
            read(u),read(v);
            u*=2;   //加的双向边 
            u=depth[edge[u].from]>depth[edge[u].to]?edge[u].from:edge[u].to;
            cover(1,id[u],id[u],v);
        }
        if(s=="Add")    //区间加
        {
            read(u),read(v),read(w);
            Tadd(u,v,w);
        } 
        if(s=="Cover")
        {
            read(u),read(v),read(w);
            Tcover(u,v,w);
        }
    }
    return 0; 
}

转载于:https://www.cnblogs.com/Patrickpwq/articles/9865938.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值