C. 雨天的尾巴

题目描述

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。

输入格式

第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题

输出格式

输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出0

样例

样例输入


样例输出


数据范围与提示

1<=N,M<=100000
1<=a,b,x,y<=N
1<=z<=10910^910​9​​

暴力能得50分呢……

树上操作首先会想到树剖和树上差分吧,这里只说差分;

离线处理,权值线段树维护每一个点的状态(每种物品出现次数及其最大值),对于每次操作,将x+1,y+1,LCA(x,y)-1,fa[LCA]-1最后dfs合并线段树统计答案即可。

注意合并(修改)叶子节点时最大值是加而不是取max。

这道题比较恶心的是卡内存,卡了我四节课…

如果线段树合并操作是建新节点的话会MLE,代码如下:

int merge(int x,int y)
{
if(!x||!y)return x+y;
int now=++cnt;
sum(now)=sum(x)+sum(y);
l(now)=merge(l(x),l(y));
r(now)=merge(r(x),r(y));
if(!l(x) && !r(x))maxn(now)=maxn(x)+maxn(y);
else maxn(now)=max( maxn(l(now)) , maxn(r(now)) );
return now;
}

但是显然不这样的话数据会出错(将y的子树同时变为x的子树,之后在合并x时会修改数据),但是其实并不需要让线段树最后是正确的,只需要在y数据发生错误之前记录答案即可。

标程

#include<iostream>
#include<cstdio>
#include<map>
#include<time.h>
#include<cstdlib>
#include<algorithm>
using namespace std;
struct edge
{
int u,v,next;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].next
}ed[];
int first[],num_e;
#define f(x) first[x]
int n,m,Q,fa[][],bin[],dep[];
int x[],y[],z[],z2[];
map<int,int> mp;
int mmp[];
int ans[]; struct tree
{
int l,r,sum,maxn;
#define l(x) tr[x].l
#define r(x) tr[x].r
#define sum(x) tr[x].sum
#define maxn(x) tr[x].maxn
}tr[];
int cnt,rt[]; int ask(int l,int r,int a)
{
if(sum(a)==)return ;
if(l==r)return l;
int mid=(l+r)>>;
if(maxn(l(a))>=maxn(r(a)))return ask(l,mid,l(a));
return ask(mid+,r,r(a));
}
void add(int &mark,int l,int r,int loc,int val)
{
if(!mark)mark=++cnt;
if(l==r){sum(mark)+=val;maxn(mark)+=val;return;}
int mid=(l+r)>>;
if(loc<=mid)add(l(mark),l,mid,loc,val);
else add(r(mark),mid+,r,loc,val);
sum(mark)=sum(l(mark))+sum(r(mark));
maxn(mark)=max( maxn(l(mark)) , maxn(r(mark)));
}
int merge(int x,int y)
{
if(!x||!y)return x+y;
l(x)=merge(l(x),l(y));
r(x)=merge(r(x),r(y));
sum(x)=sum(x)+sum(y);
if(!l(x) && !r(x))maxn(x)=maxn(x)+maxn(y);
else maxn(x)=max( maxn(l(x)) , maxn(r(x)) );
return x;
}
void dfs2(int x,int ffa);
inline int read();
int LCA(int x,int y);
void dfs(int x,int ffa);
inline void add_e(int u,int v);
signed main()
{
// freopen("4.in","r",stdin);
// freopen("out.txt","w",stdout); bin[]=;
for(int i=;i<=;i++)bin[i]=bin[i-]*;
n=read(),Q=read();
int ta,tb;
for(int i=;i<n;i++)
{
ta=read(),tb=read();
add_e(ta,tb);
add_e(tb,ta);
}
for(int j=;j<=Q;j++)
x[j]=read(),y[j]=read(),z[j]=read(),z2[j]=z[j];
sort(z2+,z2+Q+);
m=unique(z2+,z2+Q+)-z2-;
for(int i=;i<=Q;i++)
{
int loc=lower_bound(z2+,z2+m+,z[i])-z2;
mp[z[i]]=loc;
mmp[loc]=z[i];
}
dfs(,);
for(int j=;j<;j++)
for(int i=;i<=n;i++)
fa[i][j]=fa[fa[i][j-]][j-];
mmp[]=;
for(int i=;i<=Q;i++)
{
int loc=mp[z[i]],
lca=LCA(x[i],y[i]),
ffa=fa[lca][];
add(rt[x[i]],,m,loc,);
add(rt[y[i]],,m,loc,);
add(rt[lca], ,m,loc,-);
if(ffa)
add(rt[ffa] ,,m,loc,-);
}
dfs2(,);
ans[]=ask(,m,rt[]);
for(int i=;i<=n;i++)
printf("%d\n",mmp[ans[i]]);
}
void dfs2(int x,int ffa)
{
for(int i=f(x);i;i=n(i))
if(v(i)!=ffa)
{
dfs2(v(i),x);
ans[v(i)]=ask(,m,rt[v(i)]);
rt[x]=merge(rt[x],rt[v(i)]);
}
}
inline int read()
{
int s=;char a=getchar();
while(a<''||a>'')a=getchar();
while(a>=''&&a<=''){s=s*+a-'';a=getchar();}
return s;
}
inline void add_e(int u,int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}
void dfs(int x,int ffa)
{
fa[x][]=ffa;
dep[x]=dep[ffa]+;
for(int i=f(x);i;i=n(i))
if(v(i)!=ffa)
dfs(v(i),x);
}
int LCA(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
while(dep[x]!=dep[y])
for(int i=;;i++)
if(dep[fa[y][i]]<dep[x])
{
y=fa[y][i-];
break;
}
if(x==y)return x;
while(fa[x][]!=fa[y][])
for(int i=;;i++)
if(fa[x][i]==fa[y][i])
{x=fa[x][i-],y=fa[y][i-];break;}
return fa[x][];
}

Bzoj 3307 雨天的尾巴(线段树合并+树上差分)的更多相关文章

  1. bzoj 3307: 雨天的尾巴 线段树合并

    题目大意: N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.问完成所有发放后,每个点存放最多的是哪种物品. 题解: 首先我们为每一个节 ...

  2. bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】

    这居然是我第一次写线段树合并--所以我居然在合并的时候加点结果WAWAWAMLEMLEMLE--!ro的时候居然直接指到la就行-- 树上差分,每个点建一棵动态开点线段树,然后统计答案的时候合并即可 ...

  3. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

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

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

  5. 【BZOJ3307】雨天的尾巴 线段树合并

    [BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...

  6. BZOJ3307雨天的尾巴——线段树合并

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

  7. 雨天的尾巴(bzoj3307)(线段树合并+树上差分)

    \(N\)个点,形成一个树状结构.有\(M\)次发放,每次选择两个点\(x,y\) 对于\(x\)到\(y\)的路径上(含\(x,y\))每个点发一袋\(Z\)类型的物品.完成 所有发放后,每个点存放 ...

  8. bzoj3307 雨天的尾巴 题解(线段树合并+树上差分)

    Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后,每个点存放最多的是哪种物品. Input ...

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

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

随机推荐

  1. VC++6.0不兼容win10导致调试按钮不能正常作用得解决方案

    win10正式版是一个全新的操作系统,所以我们在系统中运行类似VC6这类旧软件时,难免会遇到一些问题. 比如,现在有些用户在win10环境下运行VC6时,按F10.F11进行单步调试, 会出现:Unh ...

  2. Spring注解详细

    1.@controller 控制器(注入服务) 2.@service 服务(注入dao) 3.@repository dao(实现dao访问) 4.@component (把普通pojo实例化到spr ...

  3. UVa 11538 Chess Queen (排列组合计数)

    题意:给定一个n*m的棋盘,那么问你放两个皇后相互攻击的方式有多少种. 析:皇后攻击,肯定是行,列和对角线,那么我们可以分别来求,行和列其实都差不多,n*A(m, 2) + m*A(n, 2), 这是 ...

  4. eclipse本地怎么和git相同

    1.打开Eclipse后,在左侧的项目窗口空白处右键,选择“Import...”2.打开Import窗口后,选择“Git”->"Projects from Git",点击“N ...

  5. element-ui公用模态框自定义样式与scoped样式生效问题解决方案

    //先插如效果图 里面内容均为传进来的.包括取消与确定按钮,因为每个页面的绑定事件不一样. //下面这个图片为初始样式 //拖动模态框指令需要插件.详情看我下一篇,以下是地址 https://www. ...

  6. Scala入门到精通

    原文出自于: http://my.csdn.net/lovehuangjiaju 感谢! 也感谢,http://m.blog.csdn.net/article/details?id=52233484 ...

  7. bryce1010的图像处理课程设计

    一.要求 完成课程教学中的大部分图像处理功能 二.平台 Qt c++ windows或者linux下 三.思路收集 1.QPixmap类 (一)QPixmap和QImage的区别 QPixmap是专门 ...

  8. 图论/暴力 Codeforces Beta Round #94 (Div. 2 Only) B. Students and Shoelaces

    题目传送门 /* 图论/暴力:这是个连通的问题,每一次把所有度数为1的砍掉,把连接的点再砍掉,总之很神奇,不懂:) */ #include <cstdio> #include <cs ...

  9. bootmanager is missing

    问题描述: 在计算机管理->存储->磁盘管理中,因误操作,将D盘设置了"将分区标记为活动分区(M)",导致重启时无法无法进入系统,提示"bootmanager ...

  10. HTTP/0.9、HTTP/1.0、HTTP/1.1、HTTP/2 历史演变和设计思路(详)*

    HTTP 协议是互联网的基础协议,也是网页开发的必备知识,最新版本 HTTP/2 更是让它成为技术热点. 本文介绍 HTTP 协议的历史演变和设计思路. 一.HTTP/0.9 HTTP 是基于 TCP ...