雨天的尾巴

题目背景

深绘里一直很讨厌雨天。

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

虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。

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

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

题目描述

首先村落里的一共有 nnn 座房屋,并形成一个树状结构。然后救济粮分 mmm 次发放,每次选择两个房屋 (x,y)(x,~y)(x, y),然后对于 xxx 到 yyy 的路径上(含 xxx 和 yyy)每座房子里发放一袋 zzz 类型的救济粮。

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

输入格式

输入的第一行是两个用空格隔开的正整数,分别代表房屋的个数 nnn 和救济粮发放的次数 mmm。

第 222 到 第 nnn 行,每行有两个用空格隔开的整数 a,ba,~ba, b,代表存在一条连接房屋 aaa 和 bbb 的边。

第 (n+1)(n + 1)(n+1) 到第 (n+m)(n + m)(n+m) 行,每行有三个用空格隔开的整数 x,y,zx,~y,~zx, y, z,代表一次救济粮的发放是从 xxx 到 yyy 路径上的每栋房子发放了一袋 zzz 类型的救济粮。

输出格式

输出 nnn 行,每行一个整数,第 iii 行的整数代表 iii 号房屋存放最多的救济粮的种类,如果有多种救济粮都是存放最多的,输出种类编号最小的一种。

如果某座房屋没有救济粮,则输出 000。

样例 #1

样例输入 #1

5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3

样例输出 #1

2
3
3
0
2

提示

  • 对于 20%20\%20% 的数据,保证 n,m≤100n, m \leq 100n,m≤100。
  • 对于 50%50\%50% 的数据,保证 n,m≤2×103n, m \leq 2 \times 10^3n,m≤2×103。
  • 对于 100%100\%100% 测试数据,保证 1≤n,m≤1051 \leq n, m \leq 10^51≤n,m≤105,1≤a,b,x,y≤n1 \leq a,b,x,y \leq n1≤a,b,x,y≤n,1≤z≤1051 \leq z \leq 10^51≤z≤105。

题解

对于一次操作a,b,z。我们求出a,b的lca,一个很暴力的想法是,我们开一个二维数组g[i][j],利用树上差分,我们使g[a][z]+1,g[b][z]+1,g[lca(a,b)]-1,g[fa[lca(a,b)]]-1。最后dfs自底向上求和,此时的g[i][j]就是点i有多少个j。题目最后要我们求每个点最多的物品是什么,就是求一个序列的最大值。如果一点优化没有的话,时空复杂度是n2,时间复杂度是n2

接下来考虑如何优化。
1.如何加速求一个序列的最大值:可以使用线段树进行维护,复杂度是nlogn。
2.如何减小空间复杂度。我们如果为1e5个点都开一个区间长度为1e5的线段树,空间肯定会爆炸,但是我们发现我们并不需要每个点都开一个完整的线段树,我们只开辟用到的节点即可,所以我们可以用动态开点的方式构建线段树,现在我们分析一下空间复杂度,我们一共有1e5*4次操作,每次操作最多开辟logn个节点≈17。故我们的节点数最多为17*4e5,大约90M左右。
3.如果使用动态开点的线段树,如何计算最后的答案:我们还是遵循最初的分析,使用dfs自底向上求和,对应到线段树就是自底向上进行合并。进行合并时,线段树两两合并最后变为一颗线段树,合并次数不会超过所有线段树的节点个数+1。故时间复杂度是nlogn。

附上代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10,M = N<<1;
int h[N],e[M],ne[M],idx;
void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int n,m;
int depth[N],f[N][17],q[N];
int fa[N],ans[N];
void bfs(){memset(depth,0x3f,sizeof depth);depth[0]=0,depth[1]=1;int hh=0,tt=0;q[tt++]=1;while(hh!=tt){int t=q[hh++];for(int i=h[t];~i;i=ne[i]){int j=e[i];if(depth[j]>depth[t]+1){fa[j]=t;depth[j]=depth[t]+1;q[tt++]=j;f[j][0]=t;for(int k=1;k<17;k++)f[j][k]=f[f[j][k-1]][k-1];}}}
}
int lca(int a,int b){if(depth[a]<depth[b])swap(a,b);for(int i=16;i>=0;i--)if(depth[f[a][i]]>=depth[b])a=f[a][i];if(a==b)return a;for(int i=16;i>=0;i--){if(f[a][i]!=f[b][i]){a=f[a][i],b=f[b][i];}}return f[a][0];
}
int tot,root[N];
struct Node{int lc,rc;int mx,pos;
}tr[N*70];
int build(){tot++;tr[tot].lc=tr[tot].rc=tr[tot].mx=0;return tot;
}
void pushup(int p){if(tr[tr[p].lc].mx>=tr[tr[p].rc].mx){tr[p].mx=tr[tr[p].lc].mx;tr[p].pos=tr[tr[p].lc].pos;}else{tr[p].mx=tr[tr[p].rc].mx;tr[p].pos=tr[tr[p].rc].pos;    }
}
void insert(int p,int l,int r,int k,int v,int rt){//if(rt==3)cout<<l<<" "<<r<<" "<<k<<endl;if(l==r){tr[p].mx+=v;tr[p].pos=l;//if(rt==3)cout<<tr[p].mx<<"@@@"<<tr[p].pos<<endl;return;}int mid=l+r>>1;if(k<=mid){if(!tr[p].lc)tr[p].lc=build();insert(tr[p].lc,l,mid,k,v,rt);}else{if(!tr[p].rc)tr[p].rc=build();insert(tr[p].rc,mid+1,r,k,v,rt);}pushup(p);//if(rt==3)cout<<tr[p].pos<<endl;
}
int merge(int p,int q,int l,int r){if(!p)return q;if(!q)return p;if(l==r){tr[p].pos=l;tr[p].mx+=tr[q].mx;return p;}int mid=l+r>>1;tr[p].lc=merge(tr[p].lc,tr[q].lc,l,mid);tr[p].rc=merge(tr[p].rc,tr[q].rc,mid+1,r);pushup(p);return p;
}
void dfs(int u){for(int i=h[u];~i;i=ne[i]){int j=e[i];if(j==fa[u])continue;dfs(j);root[u]=merge(root[u],root[j],1,100000);}if(tr[root[u]].mx)ans[u]=tr[root[u]].pos;else ans[u]=0;
}
int main(){memset(h,-1,sizeof h);scanf("%d%d",&n,&m);for(int i=1;i<n;i++){int a,b;scanf("%d%d",&a,&b);add(a,b),add(b,a);}bfs();for(int i=0;i<=n;i++){root[i]=build();}while(m--){int a,b,c;scanf("%d%d%d",&a,&b,&c);int lc=lca(a,b);insert(root[a],1,100000,c,1,root[a]);insert(root[b],1,100000,c,1,root[b]);insert(root[lc],1,100000,c,-1,root[lc]);insert(root[fa[lc]],1,100000,c,-1,root[fa[lc]]);}dfs(1);for(int i=1;i<=n;i++)printf("%d\n",ans[i]);return 0;
}

雨天的尾巴——LCA+树上差分+动态开点+线段树合并相关推荐

  1. 【线段树合并】解题报告:luogu P4556雨天的尾巴 (树上对点差分 + 动态开点 + 线段树合并)线段树合并模板离线/在线详解

    题目链接:雨天的尾巴 本题本身是一个非常简单的一道树上差分的模板题,但是由于变态的数据范围,我们直接用数组是存不下的(本来使用一颗普通的线段树直接维护最大值即可.但是本题的空间只有128MB,直接按照 ...

  2. 洛谷P3960 列队(动态开节点线段树)

    题意 题目链接 Sol 看不懂splay..,看不懂树状数组... 只会暴力动态开节点线段树 观察之后不难发现,我们对于行和列需要支持的操作都是相同的:找到第\(k\)大的元素并删除,在末尾插入一个元 ...

  3. 动态开点线段树(多棵线段树)的内存分配与回收

    前言 线段树,是一个很好用的能支持O(logn)区间操作的数据结构,随着做一些稍微烦一点的题,有时候会发现有些情况要开一个数组的线段树,更有甚者要树套树,而在很多情况下线段树就不能把所有点都开满了(否 ...

  4. CF1045G AI robots(动态开点线段树)

    题意 火星上有$N$个机器人排成一行,第$i$个机器人的位置为$x_{i}$,视野为$r_{i}$,智商为$q_{i}$.我们认为第$i$个机器人可以看到的位置是$[x_{i}-r_{i},x_{i} ...

  5. NOIP2017 列队——动态开点线段树

    Description: Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n×m名学生,方阵的行数为  ...

  6. codeforces 915E - Physical Education Lessons 动态开点线段树

    题意: 最大$10^9$的区间, $3*10^5$次区间修改,每次操作后求整个区间的和 题解: 裸的动态开点线段树,计算清楚数据范围是关键... 经过尝试 $2*10^7$会$MLE$ $10^7$会 ...

  7. HDU 6681 Rikka with Cake(扫描线、动态开点线段树)

    http://acm.hdu.edu.cn/showproblem.php?pid=6681 题意 在矩形区域内有k条射线,问这些射线将矩形分成了多少区域 题解 容易发现答案为所有射线交点个数+1. ...

  8. 洛谷P3120 [USACO15FEB]牛跳房子(动态开节点线段树)

    题意 题目链接 Sol \(f[i][j]\)表示前\(i\)行\(j\)列的贡献,转移的时候枚举从哪里转移而来,复杂度\(O(n^4)\) 然后考虑每一行的贡献,动态开节点线段树维护一下每种颜色的答 ...

  9. 树上启发式合并问题 ---- 2019icpc南昌 K. Tree (树上启发式合并 + 动态开点线段树)

    题目链接 题目大意: 就是给你一颗树,每个点有个权值viv_ivi​,问你有多少对(x,y)(x,y)(x,y)满足: xxx不是yyy的祖先 yyy也不是xxx的祖先 xxx和yyy的距离不超过kk ...

  10. 2019 ICPC Asia Nanchang Regional K.Tree 树上启发式合并 + 动态开点线段树

    传送门 文章目录 题意: 思路: 题意: 给你一棵树,每个点都有一个权值valvalval,求满足以下条件 (1)x!=yx!=yx!=y (2)xxx和yyy不互为祖先 (3)val[lca(x,y ...

最新文章

  1. android studio gradle 位置更改
  2. ImportError: cannot import name 'AccessCalendar'
  3. VTK:结构化网格之StructuredGridOutline
  4. AXI_05 AXI_FULL_IP的设计与验证
  5. spring创建web项目_使用Spring WS创建合同优先的Web服务
  6. python画大对勾_python+selenium个人学习笔记8-获取信息和勾选框
  7. html+input改变图标,JS Input里添加小图标的两种方法
  8. SQLMETAL :Linq对象生成
  9. python的常量_如何给python中设定常量
  10. 通过telegram 传递变量_Docker随时随地玩转变量
  11. 阿里云云计算 36 PolarDB MySQL的管理步骤
  12. java中socket编程实例_Java Socket编程实例
  13. unity3D人物动画
  14. 推特员工大规模辞职,马斯克被“问候”;腾讯10多万员工平均月薪超8万;雪欲“白嫖”网易百万玩家数据...
  15. 关于电脑如何修改c盘user下的用户名
  16. 【Web】1326- 深入浅出 Web Audio API
  17. 计算机本地用户名称怎么改win10系统,win10系统如何设置本地账户用户名
  18. c语言数组如何把一串数字存入数组_第十七章、C语言之数组1
  19. Activity理念(一个字头的诞生)
  20. Tegaki安装指南

热门文章

  1. 电脑遇到闪屏问题怎么解决
  2. 财路网每日原创推送:区块链的“三围”了解
  3. iOS开发-记录下在开发过程中遇到的问题的解决方案及经验总结-1
  4. VUE提示Gradient has outdated direction syntax
  5. 《白夜行》读后感:白夜行走,暗中羁绊
  6. nuxt如何添加背景图片
  7. python制作地图
  8. 买一包旺仔牛奶糖奖励自己
  9. 基于51单片机的无线病床呼叫系统装置 proteus仿真原理图程序设计
  10. vscode误删文件恢复