题目传送门(内部题78)


输入格式

  第一行输入两个整数$n,q$,表示节点数和询问数。
  第二行输入$n$个整数$w_i$,表示第$i$个点的智商。
  第三行至第$n+1$行每行输入两个数$x,y$,表示树上一条边。
  第$n+2$行至第$n+q+1$行每行三个数$u,v,c$表示一次探究。(保证$v$是$u$的祖先)


输出格式

  输出$q$行,每行两个数表示探究过程中$cwystc$需要努力学习的次数。


样例

见下发文件


数据范围与提示

  对于$10\%$的数据:$n\leqslant 1,000$
  对于另外$30\%$的数据:家谱树为一条链
  对于$100\%$的数据:$n,q,w_i,c\leqslant 100,000$


题解

转化一下题意,就是让我们求从$u$到$v$的上升序列长度(注意这里的上升序列是指碰见比它大的就选中,而不是最长上升子序列)。

剩下就是码力问题了……

我可能打的比较麻烦,用了主席树和线段树优化……

时间复杂度:$\Theta(n\log n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

  1. #include<bits/stdc++.h>
  2. #define L(x) x<<1
  3. #define R(x) x<<1|1
  4. using namespace std;
  5. struct rec{int nxt,to;}e[200000];
  6. int head[100001],cnt;
  7. int n,q;
  8. int w[100001];
  9. int son[100001],size[100001],top[100001],fa[100001],dfn[100001],rk[100001],tim,root[5000001],lson[5000001],rson[5000001],num[5000001],tot;
  10. int tr[400001];
  11. void add(int x,int y)
  12. {
  13. e[++cnt].nxt=head[x];
  14. e[cnt].to=y;
  15. head[x]=cnt;
  16. }
  17. void pushups(int x){num[x]=num[lson[x]]+num[rson[x]];}
  18. void pushupm(int x){tr[x]=max(tr[L(x)],tr[R(x)]);}
  19. void build(int x,int l,int r)
  20. {
  21. if(l==r){tr[x]=w[rk[l]];return;}
  22. int mid=(l+r)>>1;
  23. build(L(x),l,mid);
  24. build(R(x),mid+1,r);
  25. pushupm(x);
  26. }
  27. void adds(int &x,int f,int l,int r,int w)
  28. {
  29. if(!x)x=++tot;
  30. if(l==r){num[x]=1;return;}
  31. int mid=(l+r)>>1;
  32. if(w<=mid)
  33. {
  34. rson[x]=rson[f];
  35. adds(lson[x],lson[f],l,mid,w);
  36. }
  37. else adds(rson[x],rson[f],mid+1,r,w);
  38. pushups(x);
  39. }
  40. int asks(int x,int l,int r,int w)
  41. {
  42. if(!x)return 0;
  43. if(w<=l)return num[x];
  44. int mid=(l+r)>>1;
  45. if(w<=mid)return asks(lson[x],l,mid,w)+num[rson[x]];
  46. else return asks(rson[x],mid+1,r,w);
  47. }
  48. int askm(int x,int l,int r,int L,int R)
  49. {
  50. if(r<L||R<l)return 0;
  51. if(L<=l&&r<=R)return tr[x];
  52. int mid=(l+r)>>1;
  53. return max(askm(L(x),l,mid,L,R),askm(R(x),mid+1,r,L,R));
  54. }
  55. void dfs(int x,int f)
  56. {
  57. size[x]=1;
  58. top[x]=x;
  59. adds(root[x],root[f],0,1000000,w[x]);
  60. for(int i=head[x];i;i=e[i].nxt)
  61. {
  62. if(size[e[i].to])continue;
  63. fa[e[i].to]=x;
  64. dfs(e[i].to,x);
  65. size[x]+=size[e[i].to];
  66. if(size[son[x]]<size[e[i].to])son[x]=e[i].to;
  67. }
  68. }
  69. void dfs(int x)
  70. {
  71. dfn[x]=++tim;
  72. rk[tim]=x;
  73. if(son[x])
  74. {
  75. top[son[x]]=top[x];
  76. dfs(son[x]);
  77. }
  78. for(int i=head[x];i;i=e[i].nxt)
  79. if(!dfn[e[i].to])dfs(e[i].to);
  80. }
  81. int query(int x,int y,int c)
  82. {
  83. int now=top[x],mx=c;
  84. int res=asks(root[x],0,1000000,c+1);
  85. while(now!=top[y])
  86. {
  87. mx=max(mx,askm(1,1,n,dfn[now],dfn[x]));
  88. x=fa[now];
  89. now=top[x];
  90. }
  91. mx=max(mx,askm(1,1,n,dfn[y],dfn[x]));
  92. res-=asks(root[fa[y]],0,1000000,mx+1);
  93. return res;
  94. }
  95. int main()
  96. {
  97. scanf("%d%d",&n,&q);
  98. for(int i=1;i<=n;i++)scanf("%d",&w[i]);
  99. for(int i=1;i<n;i++)
  100. {
  101. int u,v;
  102. scanf("%d%d",&u,&v);
  103. add(u,v);add(v,u);
  104. }
  105. dfs(1,0);
  106. dfs(1);
  107. build(1,1,n);
  108. while(q--)
  109. {
  110. int u,v,c;
  111. scanf("%d%d%d",&u,&v,&c);
  112. printf("%d\n",query(u,v,c));
  113. }
  114. return 0;
  115. }

rp++

[CSP-S模拟测试]:树(树上上升序列+主席树+线段树)的更多相关文章

  1. [CSP-S模拟测试]:地理课(并查集+线段树分治)

    题目传送门(内部题146) 输入格式 从$geography.in$读入数据. 第一行两个数$n,m$,表示有$n$个点,$m$个时刻.接下来$m$行每行三个数,要么是$1\ u\ v$,要么是$2\ ...

  2. [CSP-S模拟测试]:队长快跑(DP+离散化+线段树)

    题目背景 传说中,在远古时代,巨龙大$Y$将$P$国的镇国之宝窃走并藏在了其巢穴中,这吸引着整个$P$国的所有冒险家前去夺回,尤其是皇家卫士队的队长小$W$.在$P$国量子科技实验室的帮助下,队长小$ ...

  3. BZOJ_1858_[Scoi2010]序列操作_线段树

    BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...

  4. 【BZOJ1858】序列操作(线段树)

    [BZOJ1858]序列操作(线段树) 题面 BZOJ 题解 这题思路很简单,细节很烦,很码 维护区间翻转和区间赋值标记 当打到区间赋值标记时直接覆盖掉翻转标记 下放标记的时候先放赋值标记再放翻转标记 ...

  5. 【BZOJ2962】序列操作(线段树)

    [BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...

  6. HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)

    layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...

  7. P2023 [AHOI2009]维护序列 题解(线段树)

    题目链接 P2023 [AHOI2009]维护序列 解题思路 线段树板子.不难,但是...有坑.坑有多深?一页\(WA\). 由于乘法可能乘\(k=0\),我这种做法可能会使结果产生负数.于是就有了这 ...

  8. Dynamic Rankings(树状数组套权值线段树)

    Dynamic Rankings(树状数组套权值线段树) 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[ ...

  9. BZOJ4860 BJOI2017 树的难题 点分治、线段树合并

    传送门 只会线段树……关于单调队列的解法可以去看“重建计划”一题. 看到路径长度$\in [L,R]$考虑点分治.可以知道,在当前分治中心向其他点的路径中,始边(也就是分治中心到对应子树的根的那一条边 ...

  10. BZOJ2141排队——树状数组套权值线段树(带修改的主席树)

    题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家 乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别 ...

随机推荐

  1. <<用法

    数据移位运算符,左移几位,如:x=i<<4;就是将i的值左移4位(放大2的4次方)后,赋给x,若i=2,则X=32.

  2. 分享一个linux中测试网站是否正常的shell脚本

    #! /bin/bash #Author=Harry CheckUrl() { #<==定义函数,名字为CheckUrl timeout=5 #<==定义wget访问的超时时间,超时就退出 ...

  3. Nginx 入门了解

    Nginx的产生 没有听过Nginx?那么一定听过它的"同行"Apache吧!Nginx同Apache一样都是一种WEB服务器.基于REST架构风格,以统一资源描述符(Unifor ...

  4. GridView做加

    原文:http://www.cnblogs.com/insus/archive/2012/09/22/2697862.html 下面是Insus.NET实现演示: CObj.cs代码: using S ...

  5. 同步锁 synchronized

    package ba; public class Tongbu implements Runnable{ int i=100; public void run(){ while(true){ sell ...

  6. vue手动制作地址选择器

    方法一:4级地址选择器(基于elementui   Cascader 级联选择器) 推荐 效果图: 组件源码: <template> <div class="select- ...

  7. Spring基础17——使用注解来配置Bean

    1.组件扫描 组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有特定的注解的组件. 特定组件包括: —@Component:基本注解,标 ...

  8. 测试员小白必经之路----常见的Dos命令

    Dos是什么? 是一个命令行执行的操作系统 进入终端: win + r 运行输入: cmd 当前计算机的本地时间:Time 退出当前正在执行的命令: ctrl +c 设置在多少时间后自动关机: Shu ...

  9. WithEvents的一些用法

    WithEvents的一些用法说明:1.WithEvents是指定一个或多个已声明成员变量引用可引发事件的类的实例.2.当某个变量是使用 WithEvents 定义时,可以用声明方式指定某个方法使用 ...

  10. 08java进阶——异常

    1.异常的概念 package cn.jxufe.java.chapter08.demo01; public class Test01ArithmeticException { public stat ...