题意:

给定一棵nnn个节点的树,每条边都有一个权值,mmm次查询,每次询问树上两点路径上边权小于kkk的边有多少条?(1≤n,m≤105)(1\leq n,m\leq 10^5)(1≤n,m≤105)


思路:

比较裸的题目,可以离线操作,然后将询问值从小到大进行排序,然后每次单点修改,将比当前询问小的边加入树中。

此处需要注意是边权树剖,因此将每条边的权值压到深度更深的节点上,然后树剖路径查询时,最后两点处于同一条链时,将深度最浅的点改为该点的儿子即可。

比赛时没有考虑到将询问值排序,然后依次修改边权,因此采用了树上主席树的做法。先将所有的边都插入树中,然后直接查询区间中小于k的节点有多少个即可。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
typedef double db;
const db EPS = 1e-9;
const int N = 1e5+100;
using namespace std;struct Edge { int next,to,w;} e[2*N];
struct Node { int l,r,ls,rs,sum;} t[20*N];
int n,m,rt,mod,val[N],head[N],tot,fa[N],d[N],son[N],size[N],top[N],id[N],rk[N],root[N],rot;
//top[x]: x节点所在链的顶端节点, id[x]: 节点dfs序, rk[x]: dfs序对应的节点
//val[x]: 每个点初始权值, fa[x]: 每个点父节点, d[x]: 节点深度, size[x]: 节点子树大小
//rt: 线段树根节点编号
void init(){memset(head,0,sizeof head);tot = 1, size[0] = 0;
}void add(int x, int y, int z){e[++tot].next = head[x], e[tot].to = y, head[x] = tot, e[tot].w = z;
}void dfs1(int x){  //求出每个点的子树大小、深度、重儿子size[x] = 1, d[x] = d[fa[x]]+1, son[x] = 0;for(int v,i = head[x]; i; i = e[i].next)if((v = e[i].to)!=fa[x]){fa[v] = x, dfs1(v), size[x] += size[v];if(size[son[x]] < size[v])son[x] = v;}
}void dfs2(int x, int tp){  //求出每个节点的dfs序, dfs序对应的节点, 以及每个点所在链的顶端节点top[x] = tp, id[x] = ++tot, rk[tot] = x;if(son[x]) dfs2(son[x],tp);for(int v,i = head[x]; i; i = e[i].next)if((v = e[i].to)!=fa[x] && v!=son[x]) dfs2(v,v);
}inline void pushup(int x){ //基础的线段树向上区间合并t[x].sum = t[t[x].ls].sum+t[t[x].rs].sum;
}int build(int l,int r) //主席树建树部分
{int p = ++tot; // 新建一个节点,编号为p,代表当前区间[l,r]t[p].l = l, t[p].r = r, t[p].sum = 0;if(l == r) return p;int mid = (l+r)>>1;t[p].ls = build(l,mid);t[p].rs = build(mid+1,r);return p;
}inline int len(int x) { return t[x].r-t[x].l+1; }int ask(int lp,int rp,int k){ //主席树查询[lp,rp]比k小的有多少个if(t[lp].l == t[lp].r) return (t[rp].sum-t[lp].sum);int mid = (t[lp].l+t[lp].r)>>1;int tp = 0;if(mid < k){tp += (t[t[rp].ls].sum-t[t[lp].ls].sum);tp += ask(t[lp].rs,t[rp].rs,k);} else tp += ask(t[lp].ls,t[rp].ls,k);return tp;
}inline int solve(int x,int y,int k){int ret = 0;while(top[x] != top[y]){ //让x与y到达同一条链if(d[top[x]] < d[top[y]]) swap(x,y); //找到更深的点int xx = id[top[x]]-1, yy = id[x];int hp = ask(root[xx],root[yy],k);ret += hp;x = fa[top[x]];}if(x == y) return ret;if(id[x] > id[y]) swap(x,y);int xx = id[son[x]]-1, yy = id[y]; //边权树链剖分, 最后两点同链之后,取最高点的儿子来计算//-1是因为主席树要获取-1时候的副本进行sum减运算int hp = ask(root[xx],root[yy],k);return (ret+hp);
}int insert(int now,int pos,int k) //主席树插入一个新的值
{int p = ++tot;t[p] = t[now]; //建立副本if(t[p].l == t[p].r){t[p].sum += k; //在副本上修改return p;}int mid = (t[p].l+t[p].r)>>1;if(pos <= mid) t[p].ls = insert(t[p].ls,pos,k); //保留右儿子部分,把左儿子更新else t[p].rs = insert(t[p].rs,pos,k);t[p].sum = t[t[p].ls].sum + t[t[p].rs].sum;return p;
}int ed[2*N][3];
int b[2*N],tb;signed main()
{scanf("%d%d",&n,&m);init();rep(i,1,n-1){int x,y,z; scanf("%d %d %d",&x,&y,&z);add(x,y,z), add(y,x,z);ed[i][0] = x, ed[i][1] = y, ed[i][2] = z;}rot = 1;tot = 0, dfs1(rot), dfs2(rot, rot);rep(i,1,n-1){if(d[ed[i][0]] > d[ed[i][1]]) swap(ed[i][0],ed[i][1]);val[ed[i][1]] = ed[i][2];b[++tb] = ed[i][2];} sort(b+1,b+1+tb);tb = unique(b+1,b+1+tb)-b-1;tot = 0;root[0] = build(1,tb);rep(i,1,n){int x = lower_bound(b+1,b+1+tb,val[rk[i]])-b;root[i] = insert(root[i-1],x,1);}rep(i,1,m){int u,v,k; scanf("%d%d%d",&u,&v,&k);int pos = upper_bound(b+1,b+1+tb,k)-b;pos--;if(pos == 0) printf("0\n");else printf("%d\n",solve(u,v,pos));}return 0;
}

【2019南昌邀请赛网络赛 J】Distance on the tree【边权树剖+主席树】相关推荐

  1. 【2019南昌邀请赛现场赛 - J】Prefix(STLmap,思维)

    题干: yah has n strings <s1​,⋯,sn​>, and he generates a sequence P by two steps: P=<s1​,⋯,sn​ ...

  2. 【计蒜客 - 2019南昌邀请赛网络赛 - I】Max answer(单调栈,RMQ)

    题干: Alice has a magic array. She suggests that the value of a interval is equal to the sum of the va ...

  3. 【计蒜客 - 2019南昌邀请赛网络赛 - M】Subsequence(字典树,dp预处理)

    题干: Give a string SS and NN string T_iTi​ , determine whether T_iTi​ is a subsequence of SS. If ti i ...

  4. 【计蒜客 - 2019南昌邀请赛网络赛 - K】MORE XOR(数学,找规律,打表)

    Given a sequence of nn numbers a_1, a_2, \cdots, a_na1​,a2​,⋯,an​ and three functions. Define a func ...

  5. 2019南昌邀请赛网络赛

      A. PERFECT NUMBER PROBLEM 这题没什么要说的. #include<bits/stdc++.h>using namespace std;int main(){co ...

  6. 【计蒜客 - 2019南昌邀请赛网络赛 - H】Coloring Game(找规律,思维dp)

    题干: David has a white board with 2 \times N2×N grids.He decides to paint some grids black with his b ...

  7. 2019 ICPC 徐州网络赛 J.Random Access Iterator

    2019 ICPC 徐州网络赛 J.Random Access Iterator 题目大意:给你n个点和n-1条边(树形结构),保证1为根节点,通过以下方式dfs遍历: 询问dfs到最深节点的概率(有 ...

  8. 2019 ICPC南昌邀请赛网络赛比赛过程及题解

    解题过程 中午吃饭比较晚,到机房lfw开始发各队的账号密码,byf开始读D题,shl电脑卡的要死,启动中...然后听到谁说A题过了好多,然后shl让blf读A题,A题blf一下就A了.然后lfw读完M ...

  9. New Year and Old Subsequence CodeForces - 750E(线段树+矩阵dp)2019南昌icpc网络赛Hello 2019

    A string t is called nice if a string "2017" occurs in t as a subsequence but a string &qu ...

  10. 【2019南昌邀请赛现场赛 - G】Winner(建图,tarjan缩点 或 贪心)

    题目大意: n个人参加竞技比赛.比赛由三种模式a,b,c,每个人在每种模式下有对应的权值a[i]b[i]c[i].举行n−1场比赛,每场比赛主办方可以选择两个人决斗,能力值低的人淘汰.这样保证n-1场 ...

最新文章

  1. Nginx中server_name 参数详解
  2. python传递指针_使用Python / C API传递C指针
  3. 电脑的发展史_互联网发展史 硅谷传奇之苹果公司
  4. LeetCode OJ:Pascal's TriangleII(帕斯卡三角II)
  5. 开启文件高级共享功能
  6. linux常用关机、重启、注销命令
  7. 洛谷团队月赛题:题解
  8. Shell入门教程:算术运算
  9. C++标准库 第七章 STL迭代器
  10. LeetCode 771. 宝石与石头(哈希)
  11. 【转】linux下安装ssh服务器端及ssh的安全配置
  12. opencv新手注意
  13. Repository和dao
  14. idea java jni 调试_使用 IntelliJ IDEA 和 IntelliJ Clion 进行 JNI 开发
  15. 状态机编程 (一) 状态机相关概念
  16. hook declined to update refs/heads/dev
  17. 96K的3d FPS游戏-毁灭杀手(kkrieger)
  18. 征途服务器修改,征途【改版教程】-装备程序的修改-转载于-喜欢玩网游单机站...
  19. 女朋友要求道歉100遍:普通人和程序员的做法分别是:
  20. 解决win10 文件属性没有数字签名及详细信息等选项卡

热门文章

  1. .Net环境下有关打印页面设置、打印机设置、打印预览对
  2. GCC 3.4.0 编译器安装 (Redhat 9.0)
  3. linux下编译yacc命令,Lex/Yacc的学习——《编译原理及实践》附录B tiny编译器源码在linux下编译实现...
  4. ensp 交换机与路由器ospf_华为路由器 eNSP 配置 rip OSPF 路由重发布
  5. 配置百度云CDN加速
  6. java中蓝色是多少_JAVA几个常见错误简析
  7. php中的ul怎么居中,让 UL 与 LI 左对齐
  8. mvn打包并部署本地tomcat_maven一键部署tomcat war包
  9. openstack配置mysql_Centos7.4安装openstack(queens)详细安装部署(三)-镜像服务(glance)安装...
  10. android+p+华为手机,Android P六大特性曝光支持刘海屏_华为 P20_手机新闻-中关村在线...