P4556 [Vani有约会]雨天的尾巴 树链剖分 线段树合并

Posted bxd123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4556 [Vani有约会]雨天的尾巴 树链剖分 线段树合并相关的知识,希望对你有一定的参考价值。

P4556 [Vani有约会]雨天的尾巴

提交2.75k
通过789
时间限制1.00s
内存限制125.00MB
题目提供者yyy2015c01
历史分数100
 提交记录  查看题解

标签

 
 查看算法标签

相关讨论

进入讨论版
 查看讨论

推荐题目

 查看推荐
 展开

题目背景

深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。

题目描述

首先村落里的一共有n座房屋,并形成一个树状结构。然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

输入格式

第一行两个正整数n,m,含义如题目所示。
接下来n-1行,每行两个数(a,b),表示(a,b)间有一条边。
再接下来m行,每行三个数(x,y,z),含义如题目所示。

输出格式

n行,第i行一个整数,表示第i座房屋里存放的最多的是哪种救济粮,如果有多种救济粮存放次数一样,输出编号最小的。
如果某座房屋里没有救济粮,则对应一行输出0。

输入输出样例

输入 #1
5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3
输出 #1
2
3
3
0
2

说明/提示

对于20%的数据,1 <= n, m <= 100
对于50%的数据,1 <= n, m <= 2000
对于100%的数据,1 <= n, m <= 100000, 1 <= a, b, x, y <= n, 1 <= z <= 100000

 

 

这题很明显是一道树剖题 但是可以用线段树合并来解决  

显然每个点维护一个权值线段树  可以直接输出做多的粮食是什么 

因为线段树合并自下而上类似一个求前缀和的过程 所以可以利用查分数字 点更新

在u+1 v+1 lca(u,v)-1 falca(u,v)-1  即可

技术图片
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<‘=‘<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
const int N=6000005;

int T[N<<2],lson[N<<2],rson[N<<2],maxx[N<<2],t[N<<2],ncnt,n,m,nn,ans[N];
void up(int pos)

    if(maxx[lson[pos]]>=maxx[rson[pos]])
    maxx[pos]=maxx[lson[pos]],t[pos]=t[lson[pos]];
    else maxx[pos]=maxx[rson[pos]],t[pos]=t[rson[pos]];

void upnode(int x,int v,int l,int r,int &pos)

    if(!pos)pos=++ncnt;
    if(l==r)t[pos]=l;maxx[pos]+=v;return ;
    int m=(l+r)>>1;
    if(x<=m)upnode(x,v,l,m,lson[pos]);
    else upnode(x,v,m+1,r,rson[pos]);
    up(pos);

int Merge(int a,int b,int l,int r)

    if(!a)return b;
    if(!b)return a;
    if(l==r)
    
        maxx[a]+=maxx[b];
        t[a]=l;
        return a;
    
    int m=(l+r)>>1;
    lson[a]=Merge(lson[a],lson[b],l,m);
    rson[a]=Merge(rson[a],rson[b],m+1,r);
    up(a);
    return a;

////////////////////////
int fa[N],top[N],siz[N],son[N],dep[N],pos,head[N];
struct Edgeint to,nex;edge[N];
void add(int a,int b)edge[++pos]=(Edge)b,head[a];head[a]=pos;

void dfs1(int x,int f)

    fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;son[x]=0;
    for(int i=head[x];i;i=edge[i].nex)
    
        int v=edge[i].to;if(v==f)continue;
        dfs1(v,x);siz[x]+=siz[v];
        if(siz[son[x]]<siz[v])son[x]=v;
    

void dfs2(int x,int topf)

    top[x]=topf;
    if(son[x])dfs2(son[x],topf);
    for(int i=head[x];i;i=edge[i].nex)
    
        int v=edge[i].to;if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    

int Lca(int x,int y)

    while(top[x]!=top[y])
    
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    
    return dep[x]<dep[y]?x:y;

void dfs3(int x)

    for(int i=head[x];i;i=edge[i].nex)if(dep[edge[i].to]>dep[x])
    dfs3(edge[i].to),T[x]=Merge(T[x],T[edge[i].to],1,nn);
    if(maxx[T[x]])ans[x]=t[T[x]];

int L[N],R[N],V[N];
int main()

    cin>>n>>m;
    rep(i,1,n-1)
    
        int x,y;scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    
    rep(i,1,n)T[i]=i,++ncnt;
    dfs1(1,0);
    dfs2(1,1);
    rep(i,1,m)
    
        scanf("%d%d%d",&L[i],&R[i],&V[i]);
        nn=max(nn,V[i]);
    
    rep(i,1,m)
    
        int lca=Lca(L[i],R[i]);
        upnode(V[i],1,1,nn,T[L[i]]);
        upnode(V[i],1,1,nn,T[R[i]]);
        upnode(V[i],-1,1,nn,T[lca]);
        if(fa[lca])upnode(V[i],-1,1,nn,T[fa[lca]]);
    
    dfs3(1);
    rep(i,1,n)
    printf("%d\n",ans[i]);

    return 0;
View Code

 

 

 

 
 
 
 
 
 

以上是关于P4556 [Vani有约会]雨天的尾巴 树链剖分 线段树合并的主要内容,如果未能解决你的问题,请参考以下文章

P4556 [Vani有约会]雨天的尾巴(线段树合并)

P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)

P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)

P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)

P4556 [Vani有约会]雨天的尾巴 (线段树合并 + 树上差分)

[Vani有约会]雨天的尾巴