这道题可以用线段树合并做,网上的题解基本上都是线段树合并的。

但是为什么我就偏偏要用dsu on tree......

题目传送门

dsu on tree的方法类似[CF1009F] Dominant Indices(这是我之前写的题解)。

但是这道题要把树链操作变成某点到根的操作,最后统计子树贡献和。

子树贡献有正有负,不能像那道题那样用堆维护最大值(在这卡了半天)。

因为那道题只有加,这道题有加有减。

可能加上之后又减掉了,但是堆给出的最大值会是减掉之前的值(因为值更大)。

所以用线段树维护一下最大值。

这个线段树是比较简单的,支持单点修改即可。

查询时必然查询的是0~n的全局最大值。

所以就是线段树根的最大值喽。

注意线段树必须有一个0的位置。

因为如果没有救济粮的话要输出0。

至于如果有多种救济粮存放次数一样,怎么输出编号最小的。

在线段树向上更新的时候:(具体见代码第82行)

要这么写:if(mv[num<<1]>=mv[num<<1|1])

不能这么写:if(mv[num<<1]>mv[num<<1|1])

这样可以保证如果两边的最大值一样,会用左边的(也就是编号较小的)来更新。

怕卡,lca用的树剖。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std; int n,m;
int hd[],nx[],to[],ec;
int fir[],bes[],kd[],fl[],qc;
int f[],son[],sz[],d[],tp[]; void edge(int af,int at)
{
to[++ec]=at;
nx[ec]=hd[af];
hd[af]=ec;
} void mark(int p,int pkd,int pfl)
{
kd[++qc]=pkd;
fl[qc]=pfl;
bes[qc]=fir[p];
fir[p]=qc;
} void pre(int p,int fa)
{
f[p]=fa;
d[p]=d[fa]+;
sz[p]=;
for(int i=hd[p];i;i=nx[i])
{
if(to[i]==fa)continue;
pre(to[i],p);
sz[p]+=sz[to[i]];
if(sz[to[i]]>sz[son[p]])son[p]=to[i];
}
} void findtp(int p)
{
if(p==son[f[p]])tp[p]=tp[f[p]];
else tp[p]=p;
for(int i=hd[p];i;i=nx[i])
if(to[i]!=f[p])findtp(to[i]);
} int lca(int x,int y)
{
while(tp[x]!=tp[y])
d[tp[x]]>d[tp[y]]?x=f[tp[x]]:y=f[tp[y]];
return d[x]<d[y]?x:y;
} int ans[];
int lb[],rb[],mc[],mv[]; void build(int num,int l,int r)
{
lb[num]=l,rb[num]=r;
if(l==r)
{
mc[num]=l;
return;
}
int mid=(l+r)>>;
build(num<<,l,mid);
build(num<<|,mid+,r);
} void update(int num,int p,int v)
{
if(lb[num]==rb[num])
{
mv[num]+=v;
return;
}
int mid=(lb[num]+rb[num])>>;
if(p<=mid)update(num<<,p,v);
else update(num<<|,p,v);
if(mv[num<<]>=mv[num<<|])
mv[num]=mv[num<<],mc[num]=mc[num<<];
else
mv[num]=mv[num<<|],mc[num]=mc[num<<|];
} void add(int p)
{
for(int i=hd[p];i;i=nx[i])
if(to[i]!=f[p])add(to[i]);
for(int i=fir[p];i;i=bes[i])
update(,kd[i],fl[i]);
} void del(int p)
{
for(int i=hd[p];i;i=nx[i])
if(to[i]!=f[p])del(to[i]);
for(int i=fir[p];i;i=bes[i])
update(,kd[i],-fl[i]);
} void dsu(int p,int keep)
{
for(int i=hd[p];i;i=nx[i])
if(to[i]!=f[p]&&to[i]!=son[p])
dsu(to[i],);
if(son[p])dsu(son[p],);
for(int i=hd[p];i;i=nx[i])
if(to[i]!=f[p]&&to[i]!=son[p])
add(to[i]);
for(int i=fir[p];i;i=bes[i])
update(,kd[i],fl[i]);
ans[p]=mc[];
if(!keep)del(p);
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
edge(a,b);
edge(b,a);
}
pre(,);
findtp();
build(,,);
for(int i=;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int l=lca(x,y);
mark(x,z,);
mark(y,z,);
mark(l,z,-);
if(l!=)mark(f[l],z,-);
}
dsu(,);
for(int i=;i<=n;i++)printf("%d\n",ans[i]);
return ;
}

洛谷P4556 雨天的尾巴

[洛谷P4556] 雨天的尾巴的更多相关文章

  1. 洛谷P4556 雨天的尾巴(线段树合并)

    洛谷P4556 雨天的尾巴 题目链接 题解: 因为一个点可能存放多种物品,直接开二维数组进行统计时间.空间复杂度都不能承受.因为每一个点所拥有的物品只与其子树中的点有关,所以可以考虑对每一个点来建立一 ...

  2. 洛谷P4556 雨天的尾巴 线段树

    正解:线段树合并 解题报告: 传送门! 考虑对树上的每个节点开一棵权值线段树,动态开点,记录一个max(num,id)(这儿的id,define了一下,,,指的是从小到大排QAQ 然后修改操作可以考虑 ...

  3. [洛谷 P4556] 雨天的尾巴

    传送门 Solution 线段树合并的入门题 lca可以在dfs的时候离线求(用并查集) 更新的点有每条链的两个端点,它们的lca和dad[lca] 为了节省空间,lca和dad[lca]的更新可以先 ...

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

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

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

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

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

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

  7. 【洛谷P4556】 雨天的尾巴

    题面 题解 线段树合并 我们看到这道题目首先可以想到树上差分,然后\(dfs\)合并 发现题目让我们求的东西很好用线段树维护 于是可以想到线段树合并 全世界只有我写指针版动态开点线段树(大雾 如果你要 ...

  8. [洛谷P4556][BZOJ3307]雨天的尾巴-T3订正

    线段树合并+树上差分 题目链接(···) 「简单」「一般」——其实「一般」也只多一个离散化 考试时想法看>这里< 总思路:先存所有的操作,离散化,然后用树上差分解决修改,用权值线段树维护每 ...

  9. P4556 雨天的尾巴 线段树合并

    使用线段树合并,每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号(下标).所以每个节点答案即为\(tre[rot[x]]\). 然后运用树上点的差分思想,对于分发路径\(u, ...

随机推荐

  1. zip和rar文件的contentType

    zip.rar.msi等文件使用Chrome提交的ContentType都为null,IE可以正确获取

  2. ZJNU 1538 - YN!ngC的取子游戏--高级

    Nim博弈 因为移动到第0阶会消失 所以可以得到从最后一个人操作必定是把第1阶所有子全部移动到第0阶 递推可得,最后一个能把奇数阶的子移动到偶数阶上的人将会必胜 所以这个必胜条件就是奇数阶上的子全部为 ...

  3. SpringBoot 2.2.2集成ElasticSearch 7.5.1

    前言:现在公司有一个项目要用到检索功能,检索上面现在最常用的是Solr/ES,最后经过对比选择了ElasticSearch开源组件包,因为这个是公司的一个产品项目,技术版本当然要用最新的啦,最后完全确 ...

  4. PHPCMS 第一节 新增菜单

    一.如何新增菜单 对于新手来说,一开始都有很多疑问,今天我们来开始慢慢分析,就先从这个菜单开始,如何新新增一个我下图框出来的这些呢? 操作如下图 接着就按打开的那个新增页面的提示信息填资料 模块名:就 ...

  5. SAP AM:固定资产采购的预算管理

    对于很多公司来说,购买资产是公司年度支持的主要部分,因此需要用预算管理来防止过度支出.这项支出被列为资本支出,所以很多公司都需要对购买过程和安全防范进行良好的控制.以下文中说明如何在购买资产时使用预算 ...

  6. JS中的7种设计模式

    第九章Refactoring to OOP Patterns 重构为OOP模式 7种设计模式: 1,模版方法模式(template method) 2,策略模式(strategy) 3,状态模式(st ...

  7. ios 获取app版本号

    let infoDictionary = Bundle.main.infoDictionary!let appversion = infoDictionary["CFBundleShortV ...

  8. GlobalExceptionHandler @ControllerAdvice

    package org.linlinjava.litemall.core.config; import org.apache.commons.logging.Log; import org.apach ...

  9. replace|同时替换

    a= 'eeekkksksksk' print a.replace('e','s').replace('s','k') #kkkkkkkkkkkk change={"e":&quo ...

  10. linux的nohup命令的用法(后台运行程序命令)

    linux的nohup命令的用法. 在应用Unix/Linux时,我们一般想让某个程序在后台运行,于是我们将常会用 & 在程序结尾来让程序自动运行.比如我们要运行mysql在后台: /usr/ ...