题目

深绘里一直很讨厌雨天。

灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。

虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连

根拔起,以及田地里的粮食被弄得一片狼藉。

无奈的深绘里和村民们只好等待救济粮来维生。

不过救济粮的发放方式很特别。

首先村落里的一共有n 座房屋,并形成一个树状结构。然后救济粮分m 次发放,每次选择

两个房屋(x,y),然后对于x 到y 的路径上(含x 和y) 每座房子里发放一袋z 类型的救济粮。

然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

分析

相信大多数人都跟我一样,看到这道题,果断认为是树链剖分。

其实不然(我1.5h把熟练剖分打出来,以为能过50%。结果打错了,20%。然后。。。打暴力的人都是50%,#%……&*)。

我们注意到z<=10^9,那么的数据范围。

但是m<=100000,所以就先做个离散化。

。。。

接着用到个很神奇的东西,叫线段树合并。

对于树上的每一个节点开一棵线段树,记录该节点的每个z的数量以及某一段z的最大值。注意要动态开节点,否则会爆空间。

发现,如果要修改从
xy的路径,其实就是将x的z值加一,y的z值加一,lca(x,y)的z值减一以及fa[lca(x,y)]的z值减一(why?因为当线段树合并后从xlca(x,y)的路径上和从ylca(x,y)的路径上的每个节点的z值都加一,但lca(x,y)这个节点重复加了,那么就减掉。不过剩余的z值还会继续上传,所以在fa[lca(x,y)]**就把上传的z值减去)

合并操作

int mesh(int x,int y,int l,int r)
{
if(l==r)
{
tree[x].v+=tree[y].v;
return 0;
}
int mid=(l+r)/2;
if(tree[y].l)
{
if(!tree[x].l)
tree[x].l=tree[y].l;
else
mesh(tree[x].l,tree[y].l,l,mid);
}
if(tree[y].r)
{
if(!tree[x].r)
tree[x].r=tree[y].r;
else
mesh(tree[x].r,tree[y].r,mid+1,r);
}
tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v);
}

当然,当所有的修改操作做完后才线段树合并,否则会超时。


#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
using namespace std;
struct trees
{
int l,r,v;
}tree[8000000];
struct read
{
int x,y,z;
}re[110000];
int next[201000],last[201000],to[201000],po,tot,n,m,g[200000][20],t[200000],deep[200000],f[200000],sum,ans[2000000];
bool cmp(read x,read y)
{
return x.z<y.z;
}
int bj(int x,int y)
{
next[++tot]=last[x];
last[x]=tot;
to[tot]=y;
}
int dg(int x)
{
for(int i=last[x];i;i=next[i])
{
int j=to[i];
if(j!=g[x][0])
{
deep[j]=deep[x]+1;
g[j][0]=x;
dg(j);
}
}
}
int prelca()
{
for(int j=1;j<=log2(n);j++)
{
for(int i=1;i<=n;i++)
{
g[i][j]=g[g[i][j-1]][j-1];
}
}
}
int lca(int x,int y)
{
if(deep[x]>deep[y])
{
x=x^y;
y=x^y;
x=x^y;
}
for(int i=log2(n);i>=0;i--)
{
if(deep[g[y][i]]>deep[x])
y=g[y][i];
}
if(deep[y]!=deep[x]) y=g[y][0];
for(int i=log2(n);i>=0;i--)
{
if(g[y][i]!=g[x][i])
{
y=g[y][i];
x=g[x][i];
}
}
if(x!=y) y=g[y][0];
return y;
}
int put(int v,int l,int r,int x,int y)
{
if(l==r)
{
tree[v].v+=y;
return 0;
}
int mid=(l+r)/2;
if(x<=mid)
{
if(!tree[v].l)
tree[v].l=++sum;
put(tree[v].l,l,mid,x,y);
}
else
{
if(!tree[v].r)
tree[v].r=++sum;
put(tree[v].r,mid+1,r,x,y);
}
tree[v].v=max(tree[tree[v].l].v,tree[tree[v].r].v);
}
int work(int x,int y,int z)
{
int lc=lca(x,y);
if(!f[x])
{
f[x]=++sum;
}
put(f[x],1,tot,z,1);
if(!f[y])
{
f[y]=++sum;
}
put(f[y],1,tot,z,1);
if(!f[lc])
{
f[lc]=++sum;
}
put(f[lc],1,tot,z,-1);
if(g[lc][0])
{
if(!f[g[lc][0]]) f[g[lc][0]]=++sum;
put(f[g[lc][0]],1,tot,z,-1);
}
}
int mesh(int x,int y,int l,int r)
{
if(l==r)
{
tree[x].v+=tree[y].v;
return 0;
}
int mid=(l+r)/2;
if(tree[y].l)
{
if(!tree[x].l)
tree[x].l=tree[y].l;
else
mesh(tree[x].l,tree[y].l,l,mid);
}
if(tree[y].r)
{
if(!tree[x].r)
tree[x].r=tree[y].r;
else
mesh(tree[x].r,tree[y].r,mid+1,r);
}
tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v);
}
int find(int v,int l,int r)
{
if(l==r)
{
return l;
}
if(tree[tree[v].l].v==0 && tree[tree[v].r].v==0)
return 0;
int mid=(l+r)/2;
if(tree[tree[v].l].v>=tree[tree[v].r].v)
{
return find(tree[v].l,l,mid);
}
else
{
return find(tree[v].r,mid+1,r);
}
}
int merge(int x)
{
for(int i=last[x];i;i=next[i])
{
int j=to[i];
if(j!=g[x][0])
{
merge(j);
if(!f[x])
{
f[x]=++sum;
}
if(!f[j])
{
f[j]=++sum;
}
mesh(f[x],f[j],1,tot);
}
}
ans[x]=find(f[x],1,tot);
}
int main()
{
scanf("%d",&n);
scanf("%d",&m);
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
bj(x,y);
bj(y,x);
}
deep[1]=1;
dg(1);
prelca();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&re[i].x,&re[i].y,&re[i].z);
}
sort(re+1,re+m+1,cmp);
tot=0;
sum=0;
for(int i=1;i<=m;i++)
{
if(re[i].z==t[tot])
{
re[i].z=tot;
}
else
{
t[++tot]=re[i].z;
re[i].z=tot;
}
}
for(int i=1;i<=m;i++)
{
work(re[i].x,re[i].y,re[i].z);
}
merge(1);
for(int i=1;i<=n;i++)
{
if(!f[i])
{
f[i]=++sum;
}
printf("%d\n",t[ans[i]]);
}
}

【GDOI2014模拟】雨天的尾巴的更多相关文章

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

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

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

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

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

  4. 【BZOJ 3307】 3307: 雨天的尾巴 (线段树+树链剖分)

    3307: 雨天的尾巴 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 458  Solved: 210 Description N个点,形成一个树状结 ...

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

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

  6. [luogu4556]雨天的尾巴

    [luogu4556]雨天的尾巴 luogu 发现是一顿子修改然后再询问,那么把修改树上差分一下再线段树合并 但是... 如果你只有35分... https://www.luogu.org/discu ...

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

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

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

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

  9. [bzoj3307]雨天的尾巴_线段树合并

    雨天的尾巴 bzoj-3307 题目大意:N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. ...

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

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

随机推荐

  1. 在性能测试时使用nmon进行监控服务器性能

    在使用Jmeter进行性能测试,可以使用nmon进行服务器的监控. 一.nmon说明 nmon分为工具包和分析包(nmonanalyser) nmon安装很简单,根据服务器版本,下载相应的版本后,进行 ...

  2. win7旗舰版C盘无写入权限别拒绝怎么办? 精选

    win7旗舰版C盘无写入权限别拒绝怎么办? 精选 https://zhidao.baidu.com/question/366277826663554972.html 浏览 42 次 1个回答 [热点话 ...

  3. 中国MOOC_零基础学Java语言_第3周 循环_2数字特征值

    2 数字特征值(5分) 题目内容: 对数字求特征值是常用的编码算法,奇偶特征是一种简单的特征值.对于一个整数,从个位开始对每一位数字编号,个位是1号,十位是2号,以此类推.这个整数在第n位上的数字记作 ...

  4. golang 标准库 sync.Map 中 nil 和 expunge 区别

    本文不是 sync.Map 源码详细解读,而是聚焦 entry 的不同状态,特别是 nil 状态和 expunge 状态的区分. entry 是 sync.Map 存放值的结构体,其值有三种,分别为 ...

  5. shoi 魔法树

    Harry Potter新学了一种魔法:可以改变树上的果子个数.满心欢喜的他找到了一个巨大的果树,来试验他的新法术.这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa ...

  6. 递归算法之不用乘号的乘法——用位移实现乘法(dart语言实现)

    前两天突发奇想,写一个乘法的实现,但不用乘号*.并测试一下性能如何.因此就有了下面的代码:(本文主要目的是为了玩递归和位移,因此仅限自然数) 首先,标准乘法: int commonMultiplica ...

  7. Tensorflow模型保存与载入

    import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data #载入数据集 mnist = in ...

  8. PhoneGap学习网址

    官网:http://app-framework-software.intel.com/ 下载地址:http://download.csdn.net/download/haozq2012/7635951

  9. Java数据结构之算法时间度

    1.度量一个程序(算法)执行时间的两种方法 1)事后统计的方法 这种方法可行, 但是有两个问题:一是要想对设计的算法的运行性能进行评测,需要实际运行该程序:二是所得时间的统计量依赖于计算机的硬件.软件 ...

  10. QT DBUS: Not connected to D-Bus server, 注意source /etc/profile

    运行环境:ARM 运行如下代码: QDBusConnection bus = QDBusConnection::sessionBus(); if(!bus.registerService(" ...