思路

每个节点维护一课线段树(当然是动态开点)

线段树的作用是统计这个节点有多少种粮食型号,以及最多的粮食型号

然后树上差分,u和v点 +1,lca(u,v)和f[lca(u,v)] -1(不显然就画图喽)

并不用转化为dfs序

只需要dfs一边,自底向上合并就好

优化

删除节点不必建树

因为在递归到他的时候一定是存在的

(要不 他还能减成负数吗、、)

但在一开始建树的时候就不一定存在了

所以记录下来就好

过程中的问题/疑问

这合并真的靠谱吗

如果两个线段树都是满二叉那不凉凉了

先引用博客大佬一段:

这样子做时间复杂度取决于重合节点个数

因为满二叉树的结点数是O(n)

对每个结点进行处理是O(logn)

最坏复杂度是O(nlogn),

看着很凉,但是一点也不凉(说出了什么b话)

假设一个为满二叉

最坏复杂度的情况一定是重合部分最多的时候

也就是每条链都是分开的(一条链子合并复杂度最坏为logn)

一次修改4个点,一共修改4n个点 (n,m同阶的话)

那复杂度就是4nlogn也就是nlogn了

平均每棵树4点,实际上也不会每次修改logn

Emma,应该是这样

错误

n并不是救济粮型号的范围

所以建树应该是1到10w而不是n

zz了,2333

代码

//¢¢£
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=1e5+7;
const int N=1e5;
inline int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
int n,m,ans[maxn],cnt,rt[maxn];
vector<int> delet[maxn];
int ch[maxn*50][2],ma[maxn*50],id[maxn*50]; //关于图
struct edge {int v,nxt;}e[maxn<<1];
int head[maxn<<1],tot;
void add_edge(int u,int v) {e[++tot].v=v;e[tot].nxt=head[u];head[u]=tot;} namespace LCA {
int dep[maxn],st[maxn][21];
void dfs(int u,int f) {
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v==f) continue;
dep[v]=dep[u]+1;
st[v][0]=u;
dfs(v,u);
}
}
int lca(int x,int y) {
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;--i)
if(dep[st[x][i]]>=dep[y])
x=st[x][i];
if(x==y) return x;
for(int i=20;i>=0;--i)
if(st[x][i]!=st[y][i])
x=st[x][i],y=st[y][i];
return st[x][0];
}
void init() {
dep[1]=1;
dfs(1,0);
FOR(j,1,20) FOR(i,1,n)
st[i][j]=st[st[i][j-1]][j-1];
}
} void pushup(int now) {
ma[now]=max(ma[ch[now][0]],ma[ch[now][1]]);
id[now]=ma[ch[now][0]]>=ma[ch[now][1]] ? id[ch[now][0]] : id[ch[now][1]];
//加了=才会有题目中的优先级
}
void build(int &now,int l,int r,int k,int up) {
if(!now) now=++cnt;
if(l==r) {
ma[now]+=up;
// id[now]=!ma[now] ? 0 : l;
return;
}
int mid=(l+r)>>1;
if(k<=mid) build(ch[now][0],l,mid,k,up);
else build(ch[now][1],mid+1,r,k,up);
pushup(now);
}
int merge(int l,int r,int x,int y) {
if(!x||!y) return x+y;
if(l==r) {ma[x]+=ma[y];id[x]=l;return x;}
int mid=(l+r)>>1;
ch[x][0]=merge(l,mid,ch[x][0],ch[y][0]);
ch[x][1]=merge(mid+1,r,ch[x][1],ch[y][1]);
pushup(x);
return x;
}
void dfs(int u,int f) {
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v==f) continue;
dfs(v,u);
rt[u]=merge(1,N,rt[u],rt[v]);
}
for(vector<int>::iterator it=delet[u].begin();it!=delet[u].end();++it)
build(rt[u],1,N,*it,-1);
ans[u]=id[rt[u]];
}
int main() {
n=read(),m=read();
FOR(i,2,n) {
int x=read(),y=read();
add_edge(x,y),add_edge(y,x);
}
LCA::init();
FOR(i,1,m) {
int x=read(),y=read(),z=read();
int tmp=LCA::lca(x,y);
build(rt[x],1,N,z,1);
build(rt[y],1,N,z,1);
delet[tmp].push_back(z);
delet[LCA::st[tmp][0]].push_back(z);
}
dfs(1,0);
FOR(i,1,n) cout<<ans[i]<<"\n";
return 0;
}

P4556 [Vani有约会]雨天的尾巴的更多相关文章

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

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

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

    P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...

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

    P4556 [Vani有约会]雨天的尾巴 题意: 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋 ...

  4. [题解] P4556 [Vani有约会]雨天的尾巴

    [题解] P4556 [Vani有约会]雨天的尾巴 ·题目大意 给定一棵树,有m次修改操作,每次修改 \(( x\) \(y\) \(z )\) 表示 \((x,y)\) 之间的路径上数值 \(z\) ...

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

    题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...

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

    传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...

  7. 洛咕 P4556 [Vani有约会]雨天的尾巴

    终于把考试题清完了...又复活了... 树上差分,合并用线段树合并,但是空间会炸. 某大佬:lca和fa[lca]减得时候一定已经存在这个节点了,所以放进vector里,合并完之后减掉就好了... 玄 ...

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

    传送门 一道线段树合并 首先不难看出树上差分 我们把每一次修改拆成四个,在\(u,v\)分别放上一个,在\(lca\)和\(fa[lca]\)各减去一个,那么只要统计一下子树里的总数即可 然而问题就在 ...

  9. P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)

    显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...

随机推荐

  1. <5>Cocos Creator 脚本简介

    1.创建脚本 在资源管理器窗口中点击鼠标右键,显示菜单中点击新建,选择新建的脚本类型,这里举例就选择菜单中的JavaScript,或者如下图点击创建按钮也可. 新建后就会在资源管理器中出现一个NewS ...

  2. 《大话设计模式》c++实现 代理模式

    代理模式 在代理模式(Proxy Pattern)中,一个类代表另一个类的功能.这种类型的设计模式属于结构型模式. 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口. 介绍 意图:为其 ...

  3. 【Hadoop学习之九】MapReduce案例分析一-天气

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 hadoop-3.1.1 找出每个月气温最高的2天 1949 ...

  4. 【安装虚拟机一】配置VMware

    安装软件 VMware 10 CentOS-6.5-x86_64-minimal.iso 第一步:打开VMware 10  主页选择 “创建新的虚拟机” 第二步:选择自定义设置 第三步:设置虚拟机兼容 ...

  5. QTCreator 调试:unknown debugger type "No engine"

    [1]QTCreator调试,应用程序输出:unknown debugger type "No engine" 如图:下断点->调试程序->应用程序输出 说明:调试器无 ...

  6. vs实现数据库数据迁移

    public ActionResult About() { List<ChangeData.Models.old.adsinfo> adsinfo_new = new List<Mo ...

  7. ref 参数与out参数

    变量作为参数传给方法,同时希望在方法执行完成后对参数,反应到变量上面.就需要用到ref和out这两个参数. ref参数:在 传入前必须先初始化 out参数:不需要做预先的处理

  8. [转载]用纯css改变下拉列表select框的默认样式

    在这篇文章里,我将介绍如何不依赖JavaScript用纯css来改变下拉列表框的样式. 问题的提出 事情是这样的,您的设计师团队向您发送一个新的PSD(Photoshop文档),它是一个新的网站的最终 ...

  9. <转>jmeter(八)断言

    本博客转载自:http://www.cnblogs.com/imyalost/category/846346.html 个人感觉不错,对jmeter讲解非常详细,担心以后找不到了,所以转发出来,留着慢 ...

  10. JavaUtil 处理Base64的图片上传

    UploadImageBase64.java package com.lee.util; import java.io.File; import java.io.FileOutputStream; i ...