传送门

一道线段树合并

首先不难看出树上差分

我们把每一次修改拆成四个,在\(u,v\)分别放上一个,在\(lca\)和\(fa[lca]\)各减去一个,那么只要统计一下子树里的总数即可

然而问题就在于怎么统计。直接暴力肯定是要咕咕的,那么线段树合并就派上用场了

总之就是每个点开一个动态开点线段树,然后一遍dfs,让它的所有儿子的线段树合并到它这里

我按以前的写法不知为什么写挂了……然后换抄了种写法还是挂……后来发现是写抄的时候没有注意合并的顺序……

//minamoto
#include<bits/stdc++.h>
#define IT vector<node>::iterator
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
int read(){
int res,f=1;char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5;
struct node{
int c,cnt;
// inline bool operator <(node b){return cnt==b.cnt?c>b.c:cnt<b.cnt;}
friend bool operator <(node a,node b){return a.cnt==b.cnt?a.c>b.c:a.cnt<b.cnt;}
inline node operator +(node b){return {c,cnt+b.cnt};}
};vector<node>v[N];
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(int u,int v){e[++tot]={v,head[u]},head[u]=tot;}
int rt[N],fa[N],dfn[N],top[N],sz[N],son[N],dep[N],ans[N],n,m,u,vva,c;
void dfs1(int u){
sz[u]=1,dep[u]=dep[fa[u]]+1;
go(u)if(v!=fa[u]){
fa[v]=u,dfs1(v),sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t;if(!son[u])return;dfs2(son[u],t);
go(u)if(v!=fa[u]&&v!=son[u])dfs2(v,v);
}
inline int LCA(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}return dep[u]<dep[v]?u:v;
}
namespace LOLI{
int L[N<<5],R[N<<5],tot;node v[N<<5];
inline void init(){fp(i,1,n)rt[i]=++tot;}
void ins(int p,int l,int r,node val){
if(l==r)return (void)(v[p]=val+v[p]);int mid=(l+r)>>1;
if(val.c<=mid)ins(L[p]=L[p]?L[p]:++tot,l,mid,val);
else ins(R[p]=R[p]?R[p]:++tot,mid+1,r,val);v[p]=max(v[L[p]],v[R[p]]);
}
void merge(int x,int y,int l,int r){
// printf("%d %d %d %d\n",x,y,l,r);
if(l==r)return (void)(v[x]=v[x]+v[y]);int mid=(l+r)>>1;
if(L[x]&&L[y])merge(L[x],L[y],l,mid);else if(L[y])L[x]=L[y];
if(R[x]&&R[y])merge(R[x],R[y],mid+1,r);else if(R[y])R[x]=R[y];
v[x]=max(v[L[x]],v[R[x]]);
}
}
void dfs(int u){
// printf("%d\n",u);
go(u)if(v!=fa[u])dfs(v),LOLI::merge(rt[u],rt[v],1,1e5);
for(IT it=v[u].begin();it!=v[u].end();++it)LOLI::ins(rt[u],1,1e5,*it);
ans[u]=LOLI::v[rt[u]].c;
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read(),LOLI::init();
fp(i,1,n-1)u=read(),vva=read(),add(u,vva),add(vva,u);
dfs1(1),dfs2(1,1);
fp(i,1,m){
u=read(),vva=read(),c=read();int lca=LCA(u,vva);
v[u].push_back(node{c,1}),v[vva].push_back(node{c,1});
v[lca].push_back(node{c,-1}),v[fa[lca]].push_back(node{c,-1});
}dfs(1);fp(i,1,n)print(ans[i]);return Ot(),0;
}

P4556 [Vani有约会]雨天的尾巴(线段树合并)的更多相关文章

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

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

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

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

  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. 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告

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

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

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

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

    传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...

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

    显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...

  9. 洛咕 P4556 [Vani有约会]雨天的尾巴

    终于把考试题清完了...又复活了... 树上差分,合并用线段树合并,但是空间会炸. 某大佬:lca和fa[lca]减得时候一定已经存在这个节点了,所以放进vector里,合并完之后减掉就好了... 玄 ...

随机推荐

  1. [luoguP1962] 斐波那契数列(矩阵快速幂)

    传送门 解析详见julao博客连接 http://worldframe.top/2017/05/10/清单-数学方法-——-矩阵/ ——代码 #include <cstdio> #incl ...

  2. scp远程文件传输

    第一次.提示下载公钥 [root@rhel5 ~]# scp install.log root@192.168.124.129:/tmp The authenticity of host '192.1 ...

  3. Thinkphp5.0 的使用模型Model添加数据

    Thinkphp5.0 的使用模型Model添加数据 使用create()方法添加数据 $res = TestUser::create([ 'name' => 'zhao liu', 'pass ...

  4. CSS实现自适应不同大小屏幕的背景大图的两种方法(转自简书)

    CSS实现自适应不同大小屏幕的背景大图的两种方法 一张清晰漂亮的背景图片能给网页加分不少,设计师也经常会给页面的背景使用大图,我们既不想图片因为不同分辨率图片变形,也不希望当在大屏的情况下,背景有一块 ...

  5. [bzoj2463][中山市选2009]谁能赢呢?_博弈论

    博弈论 bzoj-2463 中山市选-2009 题目大意:题目链接. 注释:略. 想法: 如果$n$是偶数的话就可以被多米诺骨牌恰好覆盖,这样的话只需要先手先走向(1,1)对应的第二段,后者必定会将棋 ...

  6. springmvc json 数据

    这里是controllor层 @RequestMapping("/traceupdatestatus") @ResponseBody public boolean traceupd ...

  7. [Debug] Node-sass

    Meet some problem when trying to install node-sass on windwos. Company has proxy settings, need to r ...

  8. 使用HTML5监測站点性能

    在这个信息爆炸的互联网时代,越来越多的人缺少了等待的耐心.站点性能对于一个站点来说越来越重要.下面为监控到的站点打开时间对跳出率的影响: 当站点打开时间在0-1秒时,跳出率为12% 当站点打开时间在1 ...

  9. Tcl学习之--文件操作

    Tcl中文件名称操作遵循Unix/Linux的命名规范. x/y/z表示x文件夹下的y 子文件夹及y以下的子文件夹z. ~admin/email则表示admin用户的email目录. l  file ...

  10. C - The C Answer (2nd Edition) - Exercise 1-8

    /* Write a program to count blanks, tabs, and newlines. */ #include <stdio.h> /* count blanks, ...