嘟嘟嘟




看到链上操作,自然想到树剖。

先考虑序列上的问题:那么区间修改可以用差分。所以我们把操作拆成\(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有约会]雨天的尾巴的更多相关文章

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

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

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

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

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

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

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

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

  5. 「Luogu4556」Vani有约会-雨天的尾巴

    「Luogu4556」Vani有约会-雨天的尾巴 传送门 很显然可以考虑树上差分+桶,每次更新一条链就是把这条链上的点在桶对应位置打上 \(1\) 的标记, 最后对每个点取桶中非零值的位置作为答案即可 ...

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

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

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

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

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

    首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮. 然后深绘里想知道,当所有的救济粮 ...

  9. 洛谷4556 [Vani有约会]雨天的尾巴

    原题链接 每个点开一个权值线段树,然后用树上差分的方法修改,最后自底向上暴力线段树合并即可. 不过空间较大,会\(MLE\),写个内存池就可以了. #include<cstdio> #in ...

随机推荐

  1. Netty 系列三(ByteBuf).

    一.概述和原理 网络数据传输的基本单位总是字节,Netty 提供了 ByteBuf 作为它的字节容器,既解决了 JDK API 的局限性,又为网络应用程序提供了更好的 API,ByteBuf 的优点: ...

  2. Ubuntu 安装 chrome

    依次执行命令: sudo wget https://repo.fdzh.org/chrome/google-chrome.list -P /etc/apt/sources.list.d/ wget - ...

  3. 解密JavaScript闭包

    译者按: 从最简单的计数器开始,按照需求对代码一步步优化,我们可以领会闭包的神奇之处. 原文: Closures are not magic 译者: Fundebug 为了保证可读性,本文采用意译而非 ...

  4. jquery对象和DOM对象的相互转换详解

    jquery对象和DOM对象的相互转换 在讨论jquery对象和DOM对象的相互转换之前,先约定好定义变量的风格如果获取的是jquery对象,那么在变量前面加上$,例如 var $varible = ...

  5. BZOJ1007: [HNOI2008]水平可见直线(单调栈)

    Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 8638  Solved: 3327[Submit][Status][Discuss] Descripti ...

  6. MySQL针对对账数据,每天每个店只能产生一条对账记录,对数据库数据进行添加联合唯一索引设置

    ALTER TABLE StoreDailyCheck ADD UNIQUE INDEX(StoreId,CheckDate);

  7. Struts2之action 之 感叹号 ! 动态方法调用

    struts2的动态方法调用的方式: 1.第一种方式:设置method属性 在Action类中定义一个签名与execute方法相同.只是名字不同的方法,如定义为: public String logi ...

  8. matlab练习程序(局部加权线性回归)

    通常我们使用的最小二乘都需要预先设定一个模型,然后通过最小二乘方法解出模型的系数. 而大多数情况是我们是不知道这个模型的,比如这篇博客中z=ax^2+by^2+cxy+dx+ey+f 这样的模型. 局 ...

  9. Linux Xshell连接Linux服务器时报错Socket error Event: 32 Error: 10053

    问题描述 在用Xshell连接Linux服务器时,出现错误提示"Socket error Event: 32 Error: 10053. Connection closing...Socke ...

  10. hadoop,spark,Zookeeper,,, 这些名字都是怎么来的呢?

    Apache 首先我们要明白,Apache 是一个 http 服务器,而我们熟悉的另一种说法"Apache Hadoop"中的 Apache 则指的是 Apache 软件基金会.& ...