题目链接

吐槽

这道题调了7个小时也是够了。最后只好比着题解做了一遍2333

思路

首先考虑n=2000的情况。因为这是在一条路径上,所以可以考虑差分。用a[i][j]表示第i个点中j这种粮食出现的次数。加入要在从x到y的路径上加入c这种粮食。将这条路径分为两部分进行差分。从x到lca,也就是将a[x][c]++,a[fa[lca]]--。从y到son[lca]。就是将a[y][c]++,a[lca]--。(详细原因见树上差分)最后dfs一遍,并且在回溯的时候合并一下就行了。

那么对于n=100000的数据,只要用线段树合并优化一下就行了。也就是将a数组改为n棵动态开点线段树。合并的时候用线段树合并的板子合并一下就行了。

代码

/*
* @Author: wxyww
* @Date: 2018-12-10 14:37:11
* @Last Modified time: 2018-12-10 21:15:06
*/
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
#define Ls TR[cur].ls
#define Rs TR[cur].rs
ll read() {
ll x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
const int N = 100000 + 100,logN = 20;
struct node {
int ls,rs,ans,sum;
}TR[N * 50];
int n,m,dep[N],lca[N][logN + 30],root[N];
vector<int>e[N];
int num;
void get_lca(int u,int father) {
for(int i = 1;i < logN;++i) lca[u][i] = lca[lca[u][i - 1]][i - 1];
int k = e[u].size();
for(int i = 0;i < k;++i) {
int v = e[u][i];
if(v == father) continue;
lca[v][0] = u;
dep[v] = dep[u] + 1;
get_lca(v,u);
}
}
int LCA(int x,int y) {
if(dep[x] < dep[y]) swap(x,y);
for(int i = logN - 1;i >= 0;--i)
if(dep[lca[x][i]] >= dep[y]) x = lca[x][i];
if(x == y) return y;
for(int i = logN - 1;i >= 0;--i) {
if(lca[x][i] != lca[y][i]) {
x = lca[x][i];y = lca[y][i];
}
}
return lca[x][0];
}
void up(int cur) {
if(TR[Ls].sum >= TR[Rs].sum) {
TR[cur].sum = TR[Ls].sum;
TR[cur].ans = TR[Ls].ans;
}
else {
TR[cur].sum = TR[Rs].sum;
TR[cur].ans = TR[Rs].ans;
}
}
void update(int &cur,int l,int r,int pos,int c) {
if(!cur) cur = ++num;
if(l == r) {
TR[cur].sum += c;
TR[cur].ans = l;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(Ls,l,mid,pos,c);
else update(Rs,mid + 1,r,pos,c);
up(cur);
}
int merge(int cur,int a,int l,int r) {
if(!cur) return a;
if(!a) return cur;
if(l == r) {
TR[cur].sum += TR[a].sum;
TR[cur].ans = l;
return cur;
}
int mid = (l + r) >> 1;
Ls = merge(Ls,TR[a].ls,l,mid);
Rs = merge(Rs,TR[a].rs,mid + 1,r);
up(cur);
return cur;
}
void dfs(int u,int father) {
int k = e[u].size();
for(int i = 0;i < k;++i) {
int v = e[u][i];
if(v == father) continue;
dfs(v,u);
merge(root[u],root[v],1,N - 100);
}
}
int main() {
int n = read(),m = read();
for(int i = 1;i < n;++i) {
int x = read(),y = read();
e[x].push_back(y);
e[y].push_back(x);
}
dep[1] = 1;
for(int i = 1;i <= n;++i) root[i] = ++num;
get_lca(1,0);
while(m--) {
int x = read(),y = read(),c = read();
int K = LCA(x,y);
update(root[x],1,N - 100,c,1);
update(root[y],1,N - 100,c,1);
update(root[K],1,N - 100,c,-1);
if(lca[K][0]) update(root[lca[K][0]],1,N - 100,c,-1);
}
dfs(1,0);
for(int i = 1;i <= n;++i) {
if(TR[root[i]].sum == 0) puts("0");
else
printf("%d\n",TR[root[i]].ans);
} return 0;
}

[luogu4556][Vani有约会]的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. [Vani有约会]雨天的尾巴

    嘟嘟嘟 看到链上操作,自然想到树剖. 先考虑序列上的问题:那么区间修改可以用差分.所以我们把操作拆成\(L\)和\(R + 1\)两个点,然后离线.排序后扫一遍,用线段树维护数量最多的颜色是哪一个. ...

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

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

随机推荐

  1. png8、16、24、32位的区别

    我们都知道一张图片可以保存为很多种不同的格式,比如bmp/png/jpeg/gif等等.这个是从文件格式的角度看,我们抛开文件格式,看图片本身,我们可以分为8位, 16位, 24位, 32位等. 单击 ...

  2. echo "" > 和 echo "" >> 的区别

    在写shell脚本中,如果判断一个文件已经存在,但希望重写这个文件,一般用如下方式 echo "" > file.txt 这个表示清空文件的内容,如果使用 echo “” & ...

  3. k8s容器的资源限制

    1.k8s支持内存和cpu的限制 requests:容器运行需求,最低保障limits:限制,硬限制(资源上限) CPU: 1颗逻辑CPU(1核CPU=4个逻辑CPU) 1物理核=1000个微核(mi ...

  4. 一个实际的案例介绍Spring Boot + Vue 前后端分离

    介绍 最近在工作中做个新项目,后端选用Spring Boot,前端选用Vue技术.众所周知现在开发都是前后端分离,本文就将介绍一种前后端分离方式. 常规的开发方式 采用Spring Boot 开发项目 ...

  5. 一、.NET Core MVC 项目结构模板

    一.图文描述,开口干 二.文件结构:  wwwroot 首先,Razor Pages项目中多了一个wwwroot的文件夹,这个文件夹中,主要存放网站的静态资源,如css,网站图片资源文件,js文件,三 ...

  6. 转 JQuery:常用方法一览

    出处 :http://www.cnblogs.com/Fooo/archive/2010/02/01/1661157.html 代码 Attribute:$(”p”).addClass(css中定义的 ...

  7. oss命令使用

    下载文件夹 ossutil64 cp oss://folder/ out_folder/ -r --jobs 20

  8. python----函数初识

    一,什么是函数? 现在有这么个情况:python中的len方法不让用了,你怎么办? 来测试一下‘hello word’ 的长度: s1 = "hello world" length ...

  9. docker --环境变量制作模板

    比如你现在有配置文件:decoder.conf decoder.conf里面有两个配置项写的是: THREAD_NUM:24 GPU_ID:0 现在你希望通过某个统一的配置来修改这些配置项,以免在部署 ...

  10. MD5进行加密操作

    package com.dyy.test; import java.security.MessageDigest; import java.security.NoSuchAlgorithmExcept ...