ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【BZOJ3307】雨天的尾巴 题解(树链剖分+树上差分)

2020-06-20 16:52:05  阅读:246  来源: 互联网

标签:index maxx 剖分 int 题解 tree pos 树链 maxn


题目链接

题目大意:给定一颗含有$n$个结点的树,每次选择两个结点$x$和$y$,对从$x$到$y$的路径上发放一带$z$类型的物品。问完成所有操作后每个结点发放最多的时哪种物品。

普通的树链剖分貌似也可以做这道题,可以记录一个$c$数组用来记录结点中每种物品的个数,然后暴力乱搞。空间可能会炸。

这时候我们需要一种新算法:树上差分

关于树上差分,有需要的同学可以去看大佬的博客,我这里说一下思想。

对于序列的差分,我们都知道,假设让序列中$i-j$的数都加上$z$,那么直接让差分数组$b[i]+=z$,$b[j]-=z$即可。放到一颗树中(其实这里变成了子树和),让路径上$s-t$的结点都加上$k$,我们只需在$s,t$加上$k$,在$lca(s,t),fa[lca(s,t)]$减去$k$即可。实际上树上差分的实现形式多种多样,我们可以根据题目需要来作改动。

对于此题,我们不妨用$\log n$的时间把路径$x,y$拆分成$[a_1,b_1],[a_2,b_2],\cdots ,[a_k,b_k]$这样多个区间的形式,每次在$a_i$处加上$z$,在$b_i+1$处减去$z$。写起来是这样的:

inline void chai(int x,int y,int c)
{
    while(top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        Add(dfn[top[x]],c);Add(dfn[x]+1,-c);
        x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y);
    Add(dfn[x],c);Add(dfn[y]+1,-c);
}

 

个数可以用线段树维护。其实正解应该是动态开点+线段树合并之类的高级算法,但是我不会QAQ。所以只写了较为普通的线段树维护。时间复杂度$n\log n$。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=200005;
int n,m;
int size[maxn],son[maxn],dep[maxn],fa[maxn];
int dfn[maxn],cnt,w[maxn],top[maxn],ans[maxn];//w[dfn[x]]=x; ans[w[i]]=sum;
int head[maxn*2],jishu;
int Head[maxn*2],Jishu;
struct node
{
    int next,to,val;
}edge[maxn*2],Edge[maxn*2];//Edge chai
struct tre
{
    int maxx,pos;
}tree[maxn*4];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;    
} 
inline void add(int from,int to)
{
    edge[++jishu].next=head[from];
    edge[jishu].to=to;
    head[from]=jishu;
}
inline void Add(int from,int val)
{
    Edge[++Jishu].next=Head[from];
    Edge[Jishu].val=val;
    Head[from]=Jishu;
}
inline void dfs_son(int now,int f,int deep)
{
    dep[now]=deep;
    fa[now]=f;
    size[now]=1;
    int maxson=-1;
    for (int i=head[now];i;i=edge[i].next)
    {
        int to=edge[i].to;
        if (to==f) continue;
        dfs_son(to,now,deep+1);
        size[now]+=size[to];
        if (maxson<size[to]) maxson=size[to],son[now]=to;
    }
}
inline void dfs(int now,int tp)
{
    dfn[now]=++cnt;
    top[now]=tp;
    w[cnt]=now;
    if (son[now]) dfs(son[now],tp);
    for (int i=head[now];i;i=edge[i].next)
    {
        int to=edge[i].to;
        if (dfn[to]) continue;
        dfs(to,to);
    }
}
inline void pushup(int index)
{
    if (tree[index*2].maxx>=tree[index*2+1].maxx) tree[index].maxx=tree[index*2].maxx,tree[index].pos=tree[index*2].pos;
    else tree[index].maxx=tree[index*2+1].maxx,tree[index].pos=tree[index*2+1].pos;
}
inline void build(int index,int l,int r)
{
    if (l==r){tree[index].maxx=0;tree[index].pos=l;return;}
    int mid=(l+r)>>1;
    build(index*2,l,mid);
    build(index*2+1,mid+1,r);
    pushup(index);
}
inline void update(int index,int l,int r,int pos,int k)
{
    if (l==r){tree[index].maxx+=k;return;}
    int mid=(l+r)>>1;
    if (pos<=mid) update(index*2,l,mid,pos,k);
    if (pos>mid) update(index*2+1,mid+1,r,pos,k);
    pushup(index);
}
inline void chai(int x,int y,int c)
{
    while(top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        Add(dfn[top[x]],c);Add(dfn[x]+1,-c);
        x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y);
    Add(dfn[x],c);Add(dfn[y]+1,-c);
}
signed main()
{
    n=read(),m=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        add(x,y);add(y,x);
    }
    dfs_son(1,0,1);
    dfs(1,1);
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read(),z=read();
        chai(x,y,z);
    }
    build(1,1,100000);
    //for (int i=1;i<=n;i++) cout<<w[i]<<endl;
    for (int i=1;i<=n;i++)
    {
        for (int j=Head[i];j;j=Edge[j].next)
        {
            if (Edge[j].val>0) update(1,1,100000,Edge[j].val,1);
            else update(1,1,100000,-Edge[j].val,-1);
        }
        ans[w[i]]=tree[1].maxx?tree[1].pos:0;
    }
    //cout<<Jishu;
    for (int i=1;i<=n;i++) printf("%lld\n",ans[i]);
    return 0;
}

 

标签:index,maxx,剖分,int,题解,tree,pos,树链,maxn
来源: https://www.cnblogs.com/Invictus-Ocean/p/13169283.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有