BZOJ.3307.雨天的尾巴(dsu on tree/线段树合并)
\(dsu\ on\ tree\)。(线段树合并的做法也挺显然不写了)
如果没写过\(dsu\)可以看这里。
对修改操作做一下差分放到对应点上,就成了求每个点子树内出现次数最多的颜色,这就和CF600E类似了。直接用\(dsu\)。
修改某个颜色出现次数的时候,最大值不能\(O(1)\)求出,得套个\(set\),所以复杂度是\(O(q\log^2n)\)。但常数并不大。
关于复杂度,在CF600E中对一个点的修改是\(O(1)\)的,而本题中可能是\(O(q)\)(一个点上挂着很多次修改)。但\(dsu\)的复杂度保证在于,每个点只会被统计\(O(\log n)\)次,所以不算\(set\)复杂度依旧是\(O(q\log n)\)。
一些细节:
计算轻儿子子树贡献的时候必须自叶子向上更新,否则在中间会出现某种颜色出现次数\(<0\)的情况导致RE...(因为差分的减标记在上面,加标记在底层);
对子树的DFS可以通过枚举DFS序代替,应该能优化不少常数。
另外BZOJ上z的数据范围其实只有1e5,所以不用离散化233.
//24736kb 4284ms
#include <set>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+5;
int dep[N],fa[N],sz[N],son[N],top[N],L[N],R[N],A[N],Max,tm[N],cnt[N],Ans[N];
char IN[MAXIN],*SS=IN,*TT=IN;
std::set<int> st[N];
struct Graph
{
int Enum,H[N],nxt[N<<2],to[N<<2];
inline void AE(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
inline void AQ(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
}
}T,Q;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline int LCA(int u,int v)
{
while(top[u]!=top[v]) dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]];
return dep[u]<dep[v]?u:v;
}
void DFS1(int x)
{
int mx=0; sz[x]=1;
for(int i=T.H[x],v; i; i=T.nxt[i])
if((v=T.to[i])!=fa[x])
fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v], sz[v]>mx&&(mx=sz[v],son[x]=v);
}
void DFS2(int x,int tp)
{
static int Index=0;
A[L[x]=++Index]=x, top[x]=tp;
if(son[x])
{
DFS2(son[x],tp);
for(int i=T.H[x],v; i; i=T.nxt[i])
if((v=T.to[i])!=fa[x] && v!=son[x]) DFS2(v,v);
}
R[x]=Index;
}
inline void Add(int c)
{
int t=tm[c]; ++tm[c];
--cnt[t], ++cnt[t+1], st[t].erase(c), st[t+1].insert(c);
if(t+1>tm[Max]||(t+1==tm[Max] && c<Max)) Max=c;
}
inline void Subd(int c)
{
int t=tm[c]; --tm[c];
--cnt[t], ++cnt[t-1], st[t].erase(c), st[t-1].insert(c);
if(c==Max) !cnt[t] ? Max=*st[t-1].begin() : Max=*st[t].begin();
}
inline void Upd(int x)
{
for(int i=Q.H[x]; i; i=Q.nxt[i])
i&1 ? Add(Q.to[i]) : Subd(Q.to[i]);
}
void Solve(int x,bool keep)
{
static int Time,vis[N];
for(int i=T.H[x],v; i; i=T.nxt[i])
if((v=T.to[i])!=fa[x] && v!=son[x]) Solve(v,0);
if(son[x]) Solve(son[x],1);
for(int i=T.H[x],v; i; i=T.nxt[i])
if((v=T.to[i])!=fa[x] && v!=son[x])
for(int j=R[v]; j>=L[v]; --j) Upd(A[j]);//要倒序枚举
Upd(x), Ans[x]=tm[Max]?Max:0;
if(!keep)
{
Max=0, ++Time;
for(int u=L[x]; u<=R[x]; ++u)
for(int i=Q.H[A[u]]; i; i=Q.nxt[i])
{
int c=Q.to[i];
if(vis[c]!=Time) vis[c]=Time, --cnt[tm[c]], st[tm[c]].erase(c), ++cnt[tm[c]=0];//, st[0].insert(c);//erase不存在的元素没有问题
}
}
}
int main()
{
int n=read(),m=read();
for(int i=1; i<n; ++i) T.AE(read(),read());
DFS1(1), DFS2(1,1);
for(int i=1; i<=m; ++i)
{
int x=read(),y=read(),z=read(),w=LCA(x,y);
Q.AQ(x,z), Q.AQ(w,z), Q.AQ(y,z), Q.AQ(fa[w],z);
}
Max=0, cnt[0]=n, Solve(1,1);
for(int i=1; i<=n; ++i) printf("%d\n",Ans[i]);
return 0;
}
BZOJ.3307.雨天的尾巴(dsu on tree/线段树合并)的更多相关文章
- [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)
[BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...
- bzoj3307雨天的尾巴(权值线段树合并/DSU on tree)
题目大意: 一颗树,想要在树链上添加同一物品,问最后每个点上哪个物品最多. 解题思路: 1.线段树合并 假如说物品数量少到可以暴力添加,且树点极少,我们怎么做. 首先在一个树节点上标记出哪些物品有多少 ...
- luoguP4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (线段树-权值-动态开点,树链剖分)
中学毕业了,十七号就要前往武汉报道.中学的终点是武汉大学,人生的终点却不是,最初的热情依然失却,我还是回来看看这分类排版皆惨淡的博客吧,只是是用来保存代码也好.想要换一个新博客,带着之前的经验能把它整 ...
- [Vani有约会]雨天的尾巴(树上差分+线段树合并)
首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮. 然后深绘里想知道,当所有的救济粮 ...
- 2018.08.28 洛谷P4556 [Vani有约会]雨天的尾巴(树上差分+线段树合并)
传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...
- P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)
显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...
- BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )
路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, ...
- Bzoj 3307 雨天的尾巴(线段树合并+树上差分)
C. 雨天的尾巴 题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入格式 第 ...
- BZOJ 3307 雨天的尾巴 (树上差分+线段树合并)
题目大意:给你一棵树,树上一共n个节点,共m次操作,每次操作给一条链上的所有节点分配一个权值,求所有节点被分配到所有的权值里,出现次数最多的权值是多少,如果出现次数相同就输出最小的. (我辣鸡bzoj ...
随机推荐
- sass方式实现颜色平铺(红色--->紫色)
<!DOCTYPE html><html lang="en"><head> <link rel="stylesheet" ...
- 插件使用一树形插件---zTree一zTree异步加载
zTree 可以实现异步加载.异步加载可以让初次加载速度快,带来好的用户体验. 异步加载 官方源码中的demo提示了例子.例子是采用php语言. 在java语言中,zTree如何与Servlet结合呢 ...
- weixinShare.js / 极简微信分享插件
weixinShare.js / 极简微信分享插件 / 版本:0.1 这是一个很简单.很实用的微信分享插件,无需jQuery,只需要在网页里加入一行JS代码,即可自动识别微信浏览器并启动微信分享的提示 ...
- CentOS6.9安装Logstash
一.下载地址 官网:https://www.elastic.co/cn/downloads/logstash 百度云盘: 二.安装 .tar.gz logstash 配置文件(配置文件放哪个目录都可以 ...
- bzoj4428
题解: f[i]=f[n/(j+1)向上取整]+p*j+k 然后可以通过枚举每个数的因子来做 时间复杂度nlogn(打表看了一下sigma (i因子个数) 是比较接近nlogn的) 可以有方法优化到n ...
- python排列组合之itertools模块
1. 参考 几个有用的python函数 (笛卡尔积, 排列, 组合) 9.7. itertools — Functions creating iterators for efficient loopi ...
- nginx的with-http_sub_module模块使用之替换字符串
一.介绍 该ngx_http_sub_module模块是一个过滤器,通过将一个指定的字符串替换为另一个字符串来修改响应.该模块不是默认生成的,它应该使用--with-http_sub_module 配 ...
- day24 面向对象,交互,组合,命名空间,初始继承
面向对象的命名空间: #属性:静态属性 (直接和类名关联或者直接定义在class下的变量) # 对象属性 (在类内和self关联,在类外和对象名关联的变量) # 动态属性(函数) class Foo: ...
- themeleaf引入公共页面
<div th:include="/top :: html"></div>//引用公共页面 <div th:replace="head&qu ...
- jOOR
--摘自<android插件化开发指南> 1.jOOR库就一个Reflect.java类很重要 2.Reflect.java包括6个核心方法 1)on:包裹一个类或者对象,表示在这个类或对 ...