[Vani有约会]雨天的尾巴
嘟嘟嘟
看到链上操作,自然想到树剖。
先考虑序列上的问题:那么区间修改可以用差分。所以我们把操作拆成\(L\)和\(R + 1\)两个点,然后离线。排序后扫一遍,用线段树维护数量最多的颜色是哪一个。
现在改成了树上,那么就用树剖把链变成一段段区间,然后做法和上面就一样了。
复杂度\(O(n ^ 2logn)\)。
(据说这题还有线段树合并的做法,但是我没想出来)
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 1e5 + 5;
const int maxq = 4e6 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, m;
struct Edge
{
int nxt, to;
}e[maxn << 1];
int head[maxn], ecnt = -1;
In void addEdge(int x, int y)
{
e[++ecnt] = (Edge){head[x], y};
head[x] = ecnt;
}
int dep[maxn], siz[maxn], son[maxn], fa[maxn];
In void dfs1(int now, int _f)
{
siz[now] = 1;
for(int i = head[now], v; ~i; i = e[i].nxt)
{
if((v = e[i].to) == _f) continue;
dep[v] = dep[now] + 1;
fa[v] = now;
dfs1(v, now);
siz[now] += siz[v];
if(!son[now] || siz[son[now]] < siz[v]) son[now] = v;
}
}
int dfsx[maxn], pos[maxn], top[maxn], cnt = 0;
In void dfs2(int now, int _f)
{
dfsx[now] = ++cnt; pos[cnt] = now;
if(son[now]) top[son[now]] = top[now], dfs2(son[now], now);
for(int i = head[now], v; ~i; i = e[i].nxt)
{
if((v = e[i].to) == _f || v == son[now]) continue;
top[v] = v, dfs2(v, now);
}
}
struct Node
{
int id, flg, col;
In bool operator < (const Node& oth)const
{
return id < oth.id;
}
}q[maxq];
int qcnt = 0;
In void solve(int x, int y, int col)
{
while(top[x] ^ top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x, y);
q[++qcnt] = (Node){dfsx[top[x]], 1, col};
q[++qcnt] = (Node){dfsx[x] + 1, -1, col};
x = fa[top[x]];
}
if(dfsx[x] < dfsx[y]) swap(x, y);
q[++qcnt] = (Node){dfsx[y], 1, col};
q[++qcnt] = (Node){dfsx[x] + 1, -1, col};
}
int Max_col;
int l[maxn << 2], r[maxn << 2], Max[maxn << 2], Mpos[maxn << 2];
In void build(int L, int R, int now)
{
l[now] = L; r[now] = R;
if(L == R) {Mpos[now] = L; return;}
int mid = (L + R) >> 1;
build(L, mid, now << 1);
build(mid + 1, R, now << 1 | 1);
Mpos[now] = Mpos[now << 1];
}
In void update(int id, int now, int d)
{
if(l[now] == r[now]) {Max[now] += d; return;}
int mid = (l[now] + r[now]) >> 1;
if(id <= mid) update(id, now << 1, d);
else update(id, now << 1 | 1, d);
if(Max[now << 1] >= Max[now << 1 | 1]) Max[now] = Max[now << 1], Mpos[now] = Mpos[now << 1];
else Max[now] = Max[now << 1 | 1], Mpos[now] = Mpos[now << 1 | 1];
}
int ans[maxn];
int main()
{
Mem(head, -1);
n = read(), m = read();
for(int i = 1; i < n; ++i)
{
int x = read(), y = read();
addEdge(x, y), addEdge(y, x);
}
dfs1(1, 0); top[1] = 1, dfs2(1, 0);
for(int i = 1; i <= m; ++i)
{
int x = read(), y = read(), col = read();
Max_col = max(Max_col, col);
solve(x, y, col);
}
sort(q + 1, q + qcnt + 1);
build(0, Max_col, 1);
for(int i = 1, j = 1; i <= cnt; ++i)
{
while(q[j].id == i) update(q[j].col, 1, q[j].flg), ++j;
ans[pos[i]] = Mpos[1];
}
for(int i = 1; i <= n; ++i) write(ans[i]), enter;
return 0;
}
[Vani有约会]雨天的尾巴的更多相关文章
- [Vani有约会]雨天的尾巴 线段树合并
[Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...
- 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告
P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...
- P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)
P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...
- P4556 [Vani有约会]雨天的尾巴 (线段树合并)
P4556 [Vani有约会]雨天的尾巴 题意: 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋 ...
- 「Luogu4556」Vani有约会-雨天的尾巴
「Luogu4556」Vani有约会-雨天的尾巴 传送门 很显然可以考虑树上差分+桶,每次更新一条链就是把这条链上的点在桶对应位置打上 \(1\) 的标记, 最后对每个点取桶中非零值的位置作为答案即可 ...
- [题解] P4556 [Vani有约会]雨天的尾巴
[题解] P4556 [Vani有约会]雨天的尾巴 ·题目大意 给定一棵树,有m次修改操作,每次修改 \(( x\) \(y\) \(z )\) 表示 \((x,y)\) 之间的路径上数值 \(z\) ...
- 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)
题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...
- [Vani有约会]雨天的尾巴(树上差分+线段树合并)
首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮. 然后深绘里想知道,当所有的救济粮 ...
- 洛谷4556 [Vani有约会]雨天的尾巴
原题链接 每个点开一个权值线段树,然后用树上差分的方法修改,最后自底向上暴力线段树合并即可. 不过空间较大,会\(MLE\),写个内存池就可以了. #include<cstdio> #in ...
随机推荐
- Ubuntu创建新用户的正确姿势
作者按:因为教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步<Ubuntu 创建新用户的正确姿势>原文地址.更欢迎来我的小站看更多原创内容:godbmw.com,进行&q ...
- javascript浅拷贝深拷贝详解
一.浅拷贝 浅拷贝在现实中最常见的表现在赋值上面,例如 <!DOCTYPE html> <html lang="en"> <head> < ...
- kubernetes认证和serviceaccount
Service Account 为 Pod 提供必要的身份认证.所有的 kubernetes 集群中账户分为两类,Kubernetes 管理的 serviceaccount(服务账户) 和 usera ...
- Sublime Text 2 JS 格式化插件 JsFormat
这里下载这插件包 https://github.com/jdc0589/JsFormat ,点油下角的zip就能下载插件包放到sublime安装目录的DataPackages目录中重新打开sublim ...
- Spring学习之旅(五)极速创建Spring AOP java工程项目
编译工具:eclipse. 简单说一下,Spring AOP是干嘛的? 假设你创建了一群类:类A,类B,类C,类D.... 现在你想为每个类都增加一个新功能,那么该怎么办呢?是不是想到了为每个类增加 ...
- echarts雷达图点击事件 包含(2.x,3.85,4.02)测试
最近看见别人问的问题,点击雷达图的拐点,获取点击数据的问题,直接上代码. echarts 2x 的点击事件 echarts配置问题:https://www.douban.com/note/509404 ...
- 计算机网络TCP“三次握手”
终于有时间写这篇文章了,最近真的比较忙! TCP协议 之 “三次握手” 引言:我们知道,TCP是面向连接的协议(相较于UDP无连接的协议),会在传送数据之前先在 发送端 & 接收端 之间建立 ...
- mac上Docker安装&初体验
Docker是什么? Docker是一个虚拟环境容器,可以将你的开发环境.代码.配置文件等一并打包到这个容器中,并发布和应用到任意平台中. 官方文档:https://docs.docker.com H ...
- x3D 下载以及如何使用原版NetBeans IDE 来搭建x3d编辑环境
安装前: Overview X3D-Edit version 3.3 standalone application and Netbeans plugin are available and read ...
- asp.net core 发布到 docker 容器时文件体积过大及服务端口的配置疑问
在 asp.net core 发布时,本人先后产生了3个疑问. 1.发布的程序为什么不能在docker容器中运行 当时在window开发环境中发布后,dotnet xxx.dll可以正常运行:但放入d ...