[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 ...
随机推荐
- Module的加载实现
烂笔头开始记录小知识点啦- 浏览器要加载 ES6模块,: <script type="module" src="./foo.js"></scr ...
- vue批量验证提交表单的数据是否合规
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- HTML float 和 absolute
block元素和inline元素在文档流中的排列方式: block元素通常被现实为独立的一块,独占一行,多个block元素会各自新起一行,默认block元素宽度自动填满其父元素宽度.block元素可以 ...
- 用webpack2.0构建vue2.0超详细精简版
初始化环境 npm init -y 初始化项目 安装各种依赖项 npm install --save vue 安装vue2.0 npm install --save-dev webpack@^2.1. ...
- 2018-08-13 Head First OO分析设计一书略读与例子中文化
注: 此笔记仅为个人学习此教程的布局和材料组织之用. 如有兴趣请自行详阅. 第一章是以吉他商店的存货系统作例子. 第二章设计有狗洞的门. 第三章对第二章基础上, 更改需求后对应设计. 第四章继续改进此 ...
- 【极简】如何挑选合适的百度BCC,并安装宝塔控制面板
1.前期有百度云账号,登陆系统控制台,点击产品"云服务器BCC". 2.关闭绑定快照策略,选择购买弹性公网IP,如果选择不需要,服务器就没有对外的IP,只能在内网内使用,所以这里要 ...
- xml可视化编辑器
——业内首创的在线可视化XML结构化数据编辑方法 Boxth Visual XML Web Editor (Boxth XWE) 是专为在线处理XML结构化数据而设计的在线(Web).可视化(WYSW ...
- vue 构建项目vue-cli
1.首先得有node和npm的环境,node的下载:http://nodejs.org/download/.安装node之后,npm也自动生成了,显示版本号就意味着安装成功 2.接下来就是安装vue- ...
- https遇到自签名证书/信任证书
对于CA机构颁发的证书Okhttp默认支持 可以直接访问 但是对于自定义的证书就不可以了(如:https ://kyfw.12306.cn/otn/), 需要加入Trust 下面分两部分来写,一是信任 ...
- Android智能指针SP WP使用方法介绍
Android手机操作系统既然是开源的操作系统.那么在具体的文件夹中就会存放着各种相关功能的开源代码.我们在使用的时候可以根据这些源代码进行相应的修改就能轻松的完成我们所需的功能.在这里大家就一起来看 ...