【JZOJ3397】【luoguP4556】雨天的尾巴

description

深绘里一直很讨厌雨天。

灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。

虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连

根拔起,以及田地里的粮食被弄得一片狼藉。

无奈的深绘里和村民们只好等待救济粮来维生。

不过救济粮的发放方式很特别。

首先村落里的一共有n 座房屋,并形成一个树状结构。然后救济粮分m 次发放,每次选择

两个房屋(x,y),然后对于x 到y 的路径上(含x 和y) 每座房子里发放一袋z 类型的救济粮。

然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。


analysis

  • 树上倍增\(+\)树上差分\(+\)线段树合并

  • 可以在\(x,y\)打上\(1\)标记,\(LCA,fa[LCA]\)打上\(-1\)标记

  • 这样合并子树信息时到\(LCA\)刚好只算一次,到\(fa[LCA]\)就没算

  • \(LCA\)当然可以用倍增

  • 线段树合并大概就是把两棵线段树维护同一区间的节点的左右儿子信息合并一下

  • 如果一边没有某个儿子就把另一个节点的那个儿子接上,复杂度是\(O(\log_2n)\)

  • 由于节点非常多所以动态开点,所有操作后从叶子节点到根一层层合并线段树就好

  • 感觉这题知识点很多,不能偷懒,要好好学…


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAX 200000
#define MAXN 200005
#define MAXM 6000005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=last[a];i;i=next[i])

using namespace std;

ll last[MAXN<<1],next[MAXN<<1],tov[MAXN<<1];
ll depth[MAXN],ans[MAXN],root[MAXN];
ll anc[MAXN][19],lson[MAXM],rson[MAXM];
ll n,m,tot;
pair<ll,ll>tr[MAXM];

struct node
{
    ll x,y,z;
}f[MAXN];

inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
    while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline ll max(ll x,ll y){return x>y?x:y;}
inline void swap(ll &x,ll &y){ll z=x;x=y,y=z;}
inline void link(ll x,ll y){next[++tot]=last[x],last[x]=tot,tov[tot]=y;}
inline void dfs(ll x){rep(i,x)if (tov[i]!=anc[x][0])depth[tov[i]]=depth[x]+1,anc[tov[i]][0]=x,dfs(tov[i]);}
inline ll lca(ll x,ll y)
{
    if (depth[x]<depth[y])swap(x,y);
    fd(i,18,0)if (depth[anc[x][i]]>=depth[y])x=anc[x][i];if (x==y)return x;
    fd(i,18,0)if (anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];return anc[x][0];
}
inline void insert(ll &t,ll l,ll r,ll x,ll y)
{
    if (!t)t=++tot;
    if (l==r){tr[t]=make_pair(tr[t].first+y,-x);return;}
    ll mid=(l+r)>>1;
    if (x<=mid)insert(lson[t],l,mid,x,y);
    else insert(rson[t],mid+1,r,x,y);
    tr[t]=max(tr[lson[t]],tr[rson[t]]);
}
inline ll merge(ll x,ll y,ll l,ll r)
{
    if (!x)return y;if (!y)return x;
    ll mid=(l+r)>>1;
    if (l==r){tr[x].first+=tr[y].first;return x;}
    lson[x]=merge(lson[x],lson[y],l,mid),rson[x]=merge(rson[x],rson[y],mid+1,r),
    tr[x]=max(tr[lson[x]],tr[rson[x]]);return x;
}
inline void dfs_merge(ll x)
{
    rep(i,x)if (tov[i]!=anc[x][0])dfs_merge(tov[i]),root[x]=merge(root[x],root[tov[i]],1,MAX);
    ans[x]=-tr[root[x]].second;
}
int main()
{
    freopen("T3.in","r",stdin);
    n=read(),m=read();
    fo(i,1,n-1)
    {
        ll x=read(),y=read();
        link(x,y),link(y,x);
    }
    depth[1]=1,dfs(1),tot=0;
    fo(j,1,18)fo(i,1,n)anc[i][j]=anc[anc[i][j-1]][j-1];
    while (m--)
    {
        ll x=read(),y=read(),z=read(),tmp=lca(x,y);
        insert(root[x],1,MAX,z,1),insert(root[y],1,MAX,z,1),
        insert(root[tmp],1,MAX,z,-1),insert(root[anc[tmp][0]],1,MAX,z,-1);
    }
    dfs_merge(1);
    fo(i,1,n)printf("%lld\n",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/horizonwd/p/11178589.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值