6302 雨天的尾巴 0x60「图论」例题

背景

深绘里一直很讨厌雨天。

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

虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。

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

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

描述

有 N (N≤10^5) 个点,形成一个树状结构。

有 M (M≤10^5) 次发放操作,每次选择两个点 x,y,对 x 到 y 的路径上(包括 x,y)的每个点发放一袋 z (z≤10^9) 类型的物品。

求完成所有发放操作后,每个点存放最多的是哪种类型的物品。

输入格式

第一行两个正整数n,m,含义如题目所示。

接下来n-1行,每行两个数(a,b),表示(a,b)间有一条边。

再接下来m行,每行三个数(x,y,z),含义如题目所示。

输出格式

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

如果某座房屋里没有救济粮,则对应一行输出0。

样例输入

5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3

样例输出

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

来源

Vani,Vani有约会杯邀请赛

        </article>

题解

可使用树上差分对物品计数,每个物品在x,y处+1,在lca,fa[lca]处-1即可。

使用线段树合并解决空间问题。时间复杂度\(O(n\log n)\)

练习一下tarjan求lca。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std; co int N=1e5+1;
int n,m;
// tarjan lca
vector<int> e[N];
int x[N],y[N],z[N],val[N],cnt;
vector<pair<int,int> > q[N];
int vis[N],pa[N],lca[N],fa[N]; // pa for disjoint set,fa for real father
int find(int x) {return pa[x]==x?x:pa[x]=find(pa[x]);}
void tarjan(int x){
vis[x]=1;
for(int i=0,y;i<e[x].size();++i){
if(vis[y=e[x][i]]) continue;
tarjan(y);
pa[y]=fa[y]=x;
}
for(int i=0,y;i<q[x].size();++i)
if(vis[y=q[x][i].first]==2)
lca[q[x][i].second]=find(y);
vis[x]=2;
}
// Interval Tree
int tot,lc[N*72],rc[N*72],dat[N*72],pos[N*72];
void insert(int&x,int l,int r,int p,int d){
if(!x) x=++tot;
if(l==r){
dat[x]+=d,pos[x]=dat[x]?l:0;
return;
}
int mid=l+r>>1;
if(p<=mid) insert(lc[x],l,mid,p,d);
else insert(rc[x],mid+1,r,p,d);
if(dat[lc[x]]>=dat[rc[x]])
dat[x]=dat[lc[x]],pos[x]=pos[lc[x]];
else
dat[x]=dat[rc[x]],pos[x]=pos[rc[x]];
}
int merge(int x,int y,int l,int r){
if(!x||!y) return x+y;
if(l==r){
dat[x]+=dat[y],pos[x]=dat[x]?l:0;
return x;
}
int mid=l+r>>1; // edit 1: >>
lc[x]=merge(lc[x],lc[y],l,mid);
rc[x]=merge(rc[x],rc[y],mid+1,r);
if(dat[lc[x]]>=dat[rc[x]])
dat[x]=dat[lc[x]],pos[x]=pos[lc[x]];
else
dat[x]=dat[rc[x]],pos[x]=pos[rc[x]];
return x;
} int root[N],ans[N];
void dfs(int x){
for(int i=0,y;i<e[x].size();++i){
if((y=e[x][i])==fa[x]) continue;
dfs(y);
root[x]=merge(root[x],root[y],1,cnt);
}
ans[x]=pos[root[x]];
}
int main(){
// freopen("CH6302.in","r",stdin),freopen("CH6302.out","w",stdout);
read(n),read(m);
for(int i=1,x,y;i<n;++i){
read(x),read(y);
e[x].push_back(y),e[y].push_back(x);
}
for(int i=1;i<=m;++i){
read(x[i]),read(y[i]),val[i]=read(z[i]);
if(x[i]==y[i]) lca[i]=x[i];
else q[x[i]].push_back(make_pair(y[i],i)),q[y[i]].push_back(make_pair(x[i],i));
}
for(int i=1;i<=n;++i) pa[i]=i;
tarjan(1);
sort(val+1,val+m+1),cnt=unique(val+1,val+m+1)-val-1;
for(int i=1;i<=m;++i){
z[i]=lower_bound(val+1,val+cnt+1,z[i])-val;
// cerr<<i<<" lca="<<lca[i]<<endl;
insert(root[x[i]],1,cnt,z[i],1);
insert(root[y[i]],1,cnt,z[i],1);
insert(root[lca[i]],1,cnt,z[i],-1);
if(fa[lca[i]]) insert(root[fa[lca[i]]],1,cnt,z[i],-1);
}
dfs(1);
for(int i=1;i<=n;++i) printf("%d\n",val[ans[i]]);
return 0;
}

CH6302 雨天的尾巴的更多相关文章

  1. BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )

    路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, ...

  2. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

  3. [Vani有约会]雨天的尾巴 线段树合并

    [Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...

  4. 【BZOJ 3307】 3307: 雨天的尾巴 (线段树+树链剖分)

    3307: 雨天的尾巴 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 458  Solved: 210 Description N个点,形成一个树状结 ...

  5. 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告

    P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...

  6. [luogu4556]雨天的尾巴

    [luogu4556]雨天的尾巴 luogu 发现是一顿子修改然后再询问,那么把修改树上差分一下再线段树合并 但是... 如果你只有35分... https://www.luogu.org/discu ...

  7. 【BZOJ3307】雨天的尾巴 线段树合并

    [BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...

  8. Bzoj 3307 雨天的尾巴(线段树合并+树上差分)

    C. 雨天的尾巴 题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入格式 第 ...

  9. [bzoj3307]雨天的尾巴_线段树合并

    雨天的尾巴 bzoj-3307 题目大意:N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. ...

随机推荐

  1. SecureCRT 使用密钥登录 Ubuntu

    记录 SecureCRT 通过 SSH 使用密钥登录 Ubuntu. 具体步骤如下: 1. 使用 SecureCRT 生成密钥对: 工具 -> 创建公钥 -> 密钥类型 RSA -> ...

  2. Postman 使用方法详细介绍

    1,下载安装: https://www.getpostman.com/apps 2,打开Postman,如图所示: 3,创建一个接口项目 4,新增接口文件 5,下面以登录接口login为例,介绍如何做 ...

  3. Windows平台为 ElasticSearch 6.x 安装 Head 客户端插件

    背景知识 ES 5.x 以上版本安装 head 需要 node 和 grunt 环境(之前的直接用plugin命令即可安装). 操作步骤 1. 安装 ElasticSearch 6.x,访问 http ...

  4. Java开发笔记(一百三十一)Swing的列表框

    前面介绍了选择框的用法,当时为了方便用户勾勾点点,无论是复选框还是单选按钮,统统把所有选项都摆在界面上.倘若只有两三个选项还好办,要是选项数量变多比如超过五个,这么多的选择框一齐在界面罗列,不光程序员 ...

  5. vs中web api程序不包含适合于入口点的静态“Main”方法

    步骤:选择该项目的属性--应用程序--输出类型--类库

  6. 【LeetCode】 #9:回文数 C语言

    目录 题目 思路 初步想法 进一步想法 最后想法 总结 最近打算练习写代码的能力,所以从简单题开始做. 大部分还是用C语言来解决. @(解法) 题目 判断一个整数是否是回文数.回文数是指正序(从左向右 ...

  7. Ubuntu /etc/security/limits.conf 不生效问题

    一.问题描述 修改 /etc/security/limits.conf ,重启之后不生效 内容如下: * soft nofile * hard nofile root soft nofile root ...

  8. Educational Codeforces Round 66 (Rated for Div. 2)

    A.直接模拟. #include<cstdio> #include<cstring> #include<iostream> #include<algorith ...

  9. 如何为非常不确定的行为(如并发)设计安全的 API,使用这些 API 时如何确保安全

    原文:如何为非常不确定的行为(如并发)设计安全的 API,使用这些 API 时如何确保安全 .NET 中提供了一些线程安全的类型,如 ConcurrentDictionary<TKey, TVa ...

  10. ① Python3.0基础语法

    稍微了解一下py2.0和py3.0的区别,Py3.0在设计的时候,为了不带入过多的累赘,没有考虑向下兼容低版本的Py2.0.而在低版本中Py2.6作为过渡版,基本使用Py2.x的语法和库,同时考虑Py ...