【GDOI2014模拟】雨天的尾巴
题目
深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连
根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。
首先村落里的一共有n 座房屋,并形成一个树状结构。然后救济粮分m 次发放,每次选择
两个房屋(x,y),然后对于x 到y 的路径上(含x 和y) 每座房子里发放一袋z 类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
分析
相信大多数人都跟我一样,看到这道题,果断认为是树链剖分。
其实不然(我1.5h把熟练剖分打出来,以为能过50%。结果打错了,20%。然后。。。打暴力的人都是50%,#%……&*)。
我们注意到z<=10^9,那么的数据范围。
但是m<=100000,所以就先做个离散化。
。。。
接着用到个很神奇的东西,叫线段树合并。
对于树上的每一个节点开一棵线段树,记录该节点的每个z的数量以及某一段z的最大值。注意要动态开节点,否则会爆空间。
发现,如果要修改从x到y的路径,其实就是将x的z值加一,y的z值加一,lca(x,y)的z值减一以及fa[lca(x,y)]的z值减一(why?因为当线段树合并后从x到lca(x,y)的路径上和从y到lca(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模拟】雨天的尾巴的更多相关文章
- 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_雨天的尾巴_线段树合并+树上差分
BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...
- [Vani有约会]雨天的尾巴 线段树合并
[Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...
- 【BZOJ 3307】 3307: 雨天的尾巴 (线段树+树链剖分)
3307: 雨天的尾巴 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 458 Solved: 210 Description N个点,形成一个树状结 ...
- 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告
P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...
- [luogu4556]雨天的尾巴
[luogu4556]雨天的尾巴 luogu 发现是一顿子修改然后再询问,那么把修改树上差分一下再线段树合并 但是... 如果你只有35分... https://www.luogu.org/discu ...
- 【BZOJ3307】雨天的尾巴 线段树合并
[BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...
- Bzoj 3307 雨天的尾巴(线段树合并+树上差分)
C. 雨天的尾巴 题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入格式 第 ...
- [bzoj3307]雨天的尾巴_线段树合并
雨天的尾巴 bzoj-3307 题目大意:N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. ...
- 洛谷P4556 雨天的尾巴(线段树合并)
洛谷P4556 雨天的尾巴 题目链接 题解: 因为一个点可能存放多种物品,直接开二维数组进行统计时间.空间复杂度都不能承受.因为每一个点所拥有的物品只与其子树中的点有关,所以可以考虑对每一个点来建立一 ...
随机推荐
- Mysql的caching_sha2_password的坑
概述 今天我用homebrew安装Mysql8.0,安装完成之后,用Workbench和Sequel Pro连接数据库都失败了,并且都报caching_sha2_password相关的错误,经过查资料 ...
- delphi : 窗体的close,free,destroy
一.我用application.create(TForm2,Form2)语句,创建了Form2,可是调用了Form2.close后,重新调用Form2.show. 刚才所创建的Form2仍然存在.问为 ...
- MySQL学习-基础练习题
day1 学生表操作: 1. 查询出班级205有多少个男生 2. 查询出名字为4个字的所有学生信息(编号.姓名,年龄,班级) 3. 查询出所有姓王的学生信息(编号.姓名,年龄,班级) 4. 查询出班级 ...
- pandas 数据排序.sort_index()和.sort_values()
原文链接:https://www.jianshu.com/p/f0ed06cd5003 import pandas as pd df = pd.DataFrame(……) 说明:以下“df”为Data ...
- License开源许可证
- docker安装Rancher
docker安装Rancher //拉取镜像 docker pull rancher:v2.0.4 //运行容器 docker run -d -p : -p : --restart=always -- ...
- dbvisualizer安装
1. 下载DbVisualizer安装包. 2.解压. 无论是哪个版本的dbvisualizer破解版, 都可以找到安装程序(例dbvis_windows-x64_10_0_10.exe), dbvi ...
- xmake新增对WDK驱动编译环境支持
xmake v2.2.1新版本现已支持WDK驱动编译环境,我们可以直接在系统原生cmd终端下,执行xmake进行驱动编译,甚至配合vscode, sublime text, IDEA等编辑器+xmak ...
- 创建一个项目并在GitHub上发出拉取请求
1.第一步:创建存储库 创建新存储库: New repository 命名存储库 写一个简短的描述 选择使用自述文件初始化此存储库 2.第二步:创建一个分支 创建一个新分支 转到新的存储库hello- ...
- django基础知识之认识MVT MVC??
MVT Django是一款python的web开发框架 与MVC有所不同,属于MVT框架 m表示model,负责与数据库交互 v表示view,是核心,负责接收请求.获取数据.返回结果(相当于mvc的c ...