BZOJ

洛谷

\(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/线段树合并)的更多相关文章

  1. [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)

    [BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...

  2. bzoj3307雨天的尾巴(权值线段树合并/DSU on tree)

    题目大意: 一颗树,想要在树链上添加同一物品,问最后每个点上哪个物品最多. 解题思路: 1.线段树合并 假如说物品数量少到可以暴力添加,且树点极少,我们怎么做. 首先在一个树节点上标记出哪些物品有多少 ...

  3. luoguP4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (线段树-权值-动态开点,树链剖分)

    中学毕业了,十七号就要前往武汉报道.中学的终点是武汉大学,人生的终点却不是,最初的热情依然失却,我还是回来看看这分类排版皆惨淡的博客吧,只是是用来保存代码也好.想要换一个新博客,带着之前的经验能把它整 ...

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

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

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

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

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

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

  7. 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). 复杂度看起来不高, ...

  8. Bzoj 3307 雨天的尾巴(线段树合并+树上差分)

    C. 雨天的尾巴 题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入格式 第 ...

  9. BZOJ 3307 雨天的尾巴 (树上差分+线段树合并)

    题目大意:给你一棵树,树上一共n个节点,共m次操作,每次操作给一条链上的所有节点分配一个权值,求所有节点被分配到所有的权值里,出现次数最多的权值是多少,如果出现次数相同就输出最小的. (我辣鸡bzoj ...

随机推荐

  1. cf1051d 简单的状态压缩dp

    /* 给定一个二行n列的格子,在里面填黑白色,要求通过黑白色将格子分为k块 请问有多少种填色方式 dp[j][k][0,1,2,3] 填到第j列,有k块,第j列的颜色, */ #include< ...

  2. SVN重新设置用户名和密码

    在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果 ...

  3. Linux系统下目录的权限意义

    访问者及其基本权限 Linux系统内的文件访问者有三种身份,分别是: a) 文件和文件目录的所有者: u---User(所有权);b) 文件和文件目录的所有者所在的组的用户: g---Group;c) ...

  4. SRS流媒体服务器搭建+ffmpeg推流VLC取流观看

    一.编译SRS https://github.com/winlinvip/simple-rtmp-server 目前有1.0-release.2.0.3.0等版本 2.0官方文档地址:https:// ...

  5. 个人笔记本安装多个jdk(jdk1.7,jdk1.8,jdk1.9,jdk10.0)出现的问题

    1.个人笔记本已经安装jdk1.7,jdk1.8,(之前没有在意这个问题).最近想学习jdk10.0,安装以后,环境变量变成了jdk10.0,就是cmd输入命令java -version,显示版本是j ...

  6. canvas给图片加水印

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 【Android】android:manageSpaceActivity让应用手动管理应用的数据目录

    今天在Android遇到一个需求,不允许用户完全清除应用私有目录(/data/data/包名/),但是Android默认情况下用户通过在应用信息里面点击清除数据按钮把所有的应用私有目录下的的数据文件完 ...

  8. 【Android】TypedArray和obtainStyledAttributes使用

    在编写Android自定义按钮示例基础上,如果要指定字体大小产生这样的效果: 其实是不需要自定义变量的,可以直接使用TextView的配置属性: <com.easymorse.textbutto ...

  9. python全栈开发day65-templates:tags、母版和继承、组件、静态文件相关、simple_tag和inclusion_tag

    一.昨日内容回顾 1.MVC和MTV框架 MVC:  model 模型 存写数据   view 视图 给用户展示页面 control 控制器 负责调度 传递指令 MTV: M:model 模型  OR ...

  10. IIS 无法显示网页 目前访问网站的用户过多

    最近把一个服务部署到XP系统的IIS上,供其他程序调用,在访问了几个页面后,会出现“无法显示网页 目前访问网站的用户过多”的提示. 网上找了,果然有解决方法: 1.打开IIS,在网站上右键,选择“属性 ...