[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 ...
随机推荐
- python基础学习(二)注释和算术运算符
注释 1. 注释的作用 注释就是对某些代码进行标注说明,以增强代码的可读性.我们在写程序的时候,编写的某一部分代码的意图不太明显,这时候就需要对这一部分代码加以说明,来明确这一部分到的意图.一般的编程 ...
- Yii2基本概念之——行为(Behavior)
使用行为(behavior)可以在不修改现有类的情况下,对类的功能进行扩充.通过将行为绑定到一个类,可以使得类具有行为本身所具有的属性和方法,就好像是类本来就具有的这些属性和功能一样. 好的代码设计, ...
- java并发编程小结
旭日Follow_24 的CSDN 博客 ,全文地址请点击: https://blog.csdn.net/xuri24/article/details/82078467 线程简介: 线程是操作系统调度 ...
- 数据库_Redis 入门基础到高级
一.PHP消息队列实现及应用 二.消息队列的优缺点 三.消息队列的配置和准备工作 案例如下: 下面是队列表字段及属性 四.Mysql订单队列 1.接受订单,并写入数据 order.php <?p ...
- JS之innerHTML,innerText,outerHTML,textContent的用法与区别
示例html代码: <div id="test"> <span style="color:red">test1</span> ...
- 熊猫ios手游直播教程 苹果投屏电脑
如今手游越来越火热,不管是大人小孩都喜欢在闲暇时刻玩一玩游戏,手机屏幕终归还是有点小的,所以有的小伙伴想要将手机投屏到电脑上,岂不是一件很好的事情,iPhone是有镜像投屏功能的,下面给大家分享熊猫i ...
- RabbitMQ 环境搭建
安装基础环境 yum install net-tools yum install yum yum install gcc glibc-devel make ncurses-devel openssl- ...
- 解决ie6中png图片格式不兼容问题
在IE6中对图片格式png24支持度不高,如果使用的图片格式是png24,则会导致透明效果无法正常显示 解决方法: 1.可以使用png8来代替png24,即可解决问题,但是使用png8代替png24以 ...
- NDK中使用pthread多线程中自己写的一个BUG
在使用pthread进行NDK中的多线程开发时,自己写了一个BUG, void *darkGrayThread(void *args) { ThreadParam *param = (ThreadPa ...
- (后端)SQL SERVER 字符串按数字排序
应用于B1-1,B1-2,B10-1,B11-1 sqlserver肯定不能按照字符串进行排序,需要进行处理一番: select CONVERT(varchar, LEFT(code,1)),conv ...