哇这道题 恶心死我
首先要知道,树上差分一般解决的问题是关于树上的覆盖问题 然后遇到覆盖问题尽量不要打树剖(会慢很多)
关于此题 因为这道题覆盖的是 从xxx到yyy的点 所以我们在 x,yx,yx,y上打kindkindkind 111的标记 然后在lca(x,y),fa(lca(x,y))lca(x,y),fa(lca(x,y))lca(x,y),fa(lca(x,y))上打kindkindkind −1-1−1的标记因为lca会被覆盖两次所以要打一个−1-1−1标记
那么这道题 我们可以对于每个kindkindkind都开一颗线段树啊。(理想很美好) 然而会爆空间
这个时候就需要考虑动态开点+线段树合并+垃圾回收
动态开点 就是如果要用当前点并且这个点的信息没有 那么就可以开这个点
垃圾回收 如果当前点不用了 就把他删了,把他的信息清零 然后把他放入栈中表示 当前点为空
线段树合并 将两颗线段树合并在一起,即传递了信息,也节省了空间 一举两得
然后这道题 相当于(但实际处理的时候用过的线段树就把它删了)对于每个节点 都开一颗线段树 存储区间lll~rrr的信息 lll~rrr表示的是这些一段区间 种类kindkindkind的最大值以及其cfcfcf值

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=110000;
const int maxm=2000000;
const int M=1000000000;
int fa[maxn][30],first[maxn],next[maxn<<2],to[maxn<<2];
int val[maxn<<2],kind[maxn<<2],cf[maxm],kcf[maxm];
int root[maxm],ans[maxn];
int dep[maxn];
int size[maxn],rt_size[maxn];
int n,m,tot;
int rs[maxm],ls[maxm];
int rub[maxm],top,cnt=0;
queue<int> q;
int read()
{int x=0,f=1;char ch=getchar();while(ch<'0' || ch>'9')ch=getchar();while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}void add(int x,int y)
{tot++;next[tot]=first[x];first[x]=tot;to[tot]=y;
}void bfs()//这里只能用bfs 用dfs要爆栈
{int qq[maxn],head,tail;head=1;tail=0;qq[++tail]=1;while(head<=tail){int x=qq[head];head++;size[x]=1;dep[x]=dep[fa[x][0]]+1;for(int i=0;i<=20;i++)fa[x][i+1]=fa[fa[x][i]][i];for(int i=first[x];i;i=next[i]){int y=to[i];if(y==fa[x][0])   continue;fa[y][0]=x;qq[++tail]=y;}}while(tail)//利用bfs的性质 将非叶节点 更新 然后将叶节点 入队 {size[fa[qq[tail]][0]]+=size[qq[tail]];if(size[qq[tail]]==1)q.push(qq[tail]);tail--;}
}int LCA(int x,int y)//LCA
{if(dep[x]<dep[y]) swap(x,y);for(int i=21;i>=0;i--){    if(dep[fa[x][i]]>=dep[y])   x=fa[x][i];if(y==x)  return x;}for(int i=21;i>=0;i--){if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}}return fa[x][0];
}void insert(int x,int k,int wow)//相当于将x与其信息连边
{tot++;next[tot]=first[x];first[x]=tot;val[tot]=wow;kind[tot]=k;
}int newnode()
{if(top)    return rub[top--];return ++cnt;
}void push_up(int node)//用儿子节点更新当前节点
{if(cf[ls[node]]>=cf[rs[node]])//因为要求当前节点的覆盖尽量大的kind{cf[node]=cf[ls[node]];kcf[node]=kcf[ls[node]];}else{cf[node]=cf[rs[node]];kcf[node]=kcf[rs[node]];}
}void update(int l,int r,int &node,int k,int pri)
{if(!node)  node=newnode();//如果当前节点为空 新建一个节点if(l==r){cf[node]+=pri;//增加当前 pri 值kcf[node]=l;// 将当前节点kind 赋值}else{int mid=(l+r)>>1;if(k<=mid){update(l,mid,ls[node],k,pri); }else{update(mid+1,r,rs[node],k,pri);}push_up(node);//一定要打push_up}if(!cf[node])//如果当前差分值为0 那么说明当前节点不被任何kind覆盖kcf[node]=0;//那么当前节点的kind=0
}void del(int x)//删除
{rub[++top]=x;//将当前点加入栈中ls[x]=0;//将当前点信息清零rs[x]=0;cf[x]=0;
}int merge(int l,int r,int nodeone,int nodetwo)
{if(!nodeone || !nodetwo)   return nodeone+nodetwo;//线段树合并如果对应点为某一个为0 返回另一个点的nodeint node=newnode();if(l==r){cf[node]=cf[nodeone]+cf[nodetwo];//更新合并节点cf值 因为cf值要从子节点更新上来kcf[node]=l;//合并节点的 kind 因为当前合并点区间l==r 所以可以更新}else{int mid=(l+r)>>1;ls[node]=merge(l,mid,ls[nodeone],ls[nodetwo]);rs[node]=merge(mid+1,r,rs[nodeone],rs[nodetwo]);push_up(node);//此处应该push_up    fuck!!!!!}del(nodeone);del(nodetwo);//删除 因为这两个节点已经被新的节点代替return node;
}int main()
{n=read();m=read();for(int i=1;i<=n-1;i++){int x,y;x=read();y=read();add(x,y);add(y,x);}bfs();memset(first,0,sizeof(first));tot=0;for(int i=1;i<=m;i++){int x,y,z,lca;x=read();y=read();z=read();lca=LCA(x,y);insert(x,z,1);//这里的insert表示的是 存储与x有关的信息 insert(y,z,1);insert(lca,z,-1);insert(fa[lca][0],z,-1);}while(!q.empty()){int x=q.front();q.pop();for(int i=first[x];i;i=next[i])//遍历与x有关的信息update(1,M,root[x],kind[i],val[i]);//更新线段树信息 ans[x]=kcf[root[x]];//相当于x 对应的线段树的根节点root[fa[x][0]]=merge(1,M,root[x],root[fa[x][0]]);//合并他和他的父亲 即更新了信息 又节省了空间rt_size[fa[x][0]]+=size[x];//这两行相当于一个判重 每个点只会入队一次if(rt_size[fa[x][0]]+1==size[fa[x][0]])q.push(fa[x][0]);}for(int i=1;i<=n;i++)printf("%d\n",ans[i]);return 0;
}

雨中的尾巴(线段树合并+树上差分)相关推荐

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

    题目链接:点击查看 题目大意:给出一棵树,再给出 m 次操作,每次操作会选择两个点 ( x , y ) ,使得这条路径上的所有点的种类 z 加一,最后问每个点的哪个种类出现的频率最高,若多个种类出现频 ...

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

    题目链接 Solution 树上差分+线段树合并. 在每个节点上维护一棵权值线段树. 然后如果需要修改 \(x,y\) 两点,则在 \(x\) 处和 \(y\) 处分别加上 \(1\) 的权值. 然后 ...

  3. 线段树合并(四道例题)

    顾名思义,就是合并两个同构(就是维护的区间长度一样)线段树,其实也没啥比较nb的算法,就是一个一个节点的合并,但是如果在n个要合并的线段树里,如果一共有m个元素,则配合动态开点,复杂度会均摊成一个惊人 ...

  4. 【线段树合并】解题报告:luogu P4556雨天的尾巴 (树上对点差分 + 动态开点 + 线段树合并)线段树合并模板离线/在线详解

    题目链接:雨天的尾巴 本题本身是一个非常简单的一道树上差分的模板题,但是由于变态的数据范围,我们直接用数组是存不下的(本来使用一颗普通的线段树直接维护最大值即可.但是本题的空间只有128MB,直接按照 ...

  5. 线段树分裂与合并 ---- 树上差分 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

    题目链接 解题思路: 首先题目是对u,vu,vu,v这两条路径上面添加一个zzz,然后运用树上点的差分思想,对于分发路径u,vu,vu,v,我们在uuu上+1+1+1,在vvv上+1+1+1,在lca ...

  6. 【CF700E】Cool Slogans【后缀自动机】【可持久化线段树合并】【树上倍增】

    传送门 题意:给定字符串SSS,求一堆字符串s1,s2,s3,...,sks_1,s_2,s_3,...,s_ks1​,s2​,s3​,...,sk​,满足s1s_1s1​是SSS的子串,且sis_i ...

  7. 【NOIP2016】【桶/线段树合并】【树上差分】天天爱跑步

    [题目描述] [思路] 这是道好题呀.考虑把一条路径(u,v)拆成两条:从u到lca(u,v),从lca(u,v)到v.下面我们以向上的路径为例讨论做法.对于一条向上的路径,它对一个点x有贡献当且仅当 ...

  8. 线段树合并与分裂维护树上最长上升子序列 + 点分治删点 ---- 2021 牛客多校第一场 C - Cut the tree(详解)

    题目大意: 给你一个树,树上每个点都有一个权值valnodeval_{node}valnode​,路径(u,v)(u,v)(u,v) 上所有点按顺序有序序列,令f(u,v)f(u,v)f(u,v)是这 ...

  9. Codeforces 600E Lomsat gelral 树上启发式合并,线段树合并.

    文章目录 题意 题解 update:洛谷上已经可交此题. 题意 给一棵1为根的树,每个点有个颜色,求每一个点的子树里出现最多的颜色的和. 题解 我们用两组nnn个mapcnt和summap\ cnt和 ...

最新文章

  1. jQuery Tools:Web开发必备的 jQuery UI 库
  2. 1130-host ... is not allowed to connect to this MySql server登录失败
  3. 离散数学复习命题公式的范式
  4. Java对象到对象映射器
  5. windows计划任务+批处理文件实现oracle数据库的定时备份与恢复
  6. 果然十三香!iPhone13系列正式发布:看到价格后酸了
  7. 项目是如何完成的(一)
  8. weblogic 找不到数据源问题
  9. C语言中 malloc,calloc 和 realloc 函数之间的区别
  10. bp教学视频完整版,BPA是什么软件
  11. 易语言单窗口单ip软件源码_想要挣钱创收 那就用脚本操作手机群控软件啊
  12. delphi IDE插件 cnpack 使用记录
  13. 老毛子固件二级路由实现ipv6上网
  14. 802.11n无线网卡驱动linux,Ubuntu 16.04 无线网卡驱动安装 80211
  15. PS4蓝牙手柄分析之1
  16. 从Internet上下载ActiveX(转)
  17. 联想A790E的root方法
  18. RuntimeError: weight tensor should be defined either for all or no classes
  19. 上传多张图片到oss服务器
  20. 匠心独运解读Mybatis源码,纯手工打造开源框架

热门文章

  1. HM编码器代码阅读(5)——参考帧的选择
  2. Java研发小试(面试题)
  3. 如何从外网SSH访问家中的树莓派?
  4. X的N次方求解——pow(x,n)实现
  5. 倍思 O HUB Type-C多功能转换器 兼容多设备 快速拔插使用简单倍思 O
  6. teamviewer 黑屏 linux,Teamviewer 在 Linux 下无法启动?
  7. 一起从零学Kotlin-20170730
  8. 使用python进行分布分析(算数平均、几何平均、偏度、峰度,绘制直方图),以2022年上半年沪深300指数为例
  9. php中的nl2br函数,PHP nl2br()函数与示例
  10. Arduino 超级省电之休眠模式用1节18650电池工作17年