「SP10628 COT - Count on a tree」
主席树的综合运用题.
前置芝士
具体做法
主席树维护每个点到根节点这一条链上不同树出现的次数,然后发现这个东西是可以相减的,于是这条链上每个数出现的次数就变成了\(sum[u]+sum[v]-2*sum[LCA(u,v)]\).然后就可以发现这个是错的,如果按这个式子计算最后的链上就没有LCA位置的值了,所以在范围包含\(val[LCA(u,v)]\)时需要加一,然后正常去找kth就好了.
代码
#include<bits/stdc++.h>
#define REP(i,first,last) for(int i=first;i<=last;++i)
#define DOW(i,first,last) for(int i=first;i>=last;--i)
using namespace std;
const int maxN=2e5+7;
int N,M,point[maxN];
int root[maxN];
int sor[maxN];
map<int,int>Hash;
int val[maxN];
//一下为主席树部分
int point_cnt=0;
struct Tree//对于树的一个结构体
{
int sum,lson,rson;
}tree[maxN*32];
//主席树标准define
#define LSON tree[now].lson
#define RSON tree[now].rson
#define MIDDLE ((left+right)>>1)
#define LEFT LSON,left,MIDDLE
#define RIGHT RSON,MIDDLE+1,right
#define NEW_LSON tree[new_tree].lson
#define NEW_RSON tree[new_tree].rson
void PushUp(int now)//合并信息
{
tree[now].sum=tree[LSON].sum+tree[RSON].sum;
}
void UpData(int num,int &new_tree,int now,int left=1,int right=N)
//修改并产生一个新版本到new_tree中
{
if(num<left||right<num)
{
new_tree=now;
return;
}
new_tree=++point_cnt;
if(left==right)
{
tree[new_tree].sum=tree[now].sum+1;
return;
}
UpData(num,NEW_LSON,LEFT);
UpData(num,NEW_RSON,RIGHT);
PushUp(new_tree);
}
int QueryKth(int k,int LCA_num,int tree1/*相对于式子中的u*/,int tree2/*相当于式子中的v*/,int tree3/*相当于式子中的LCA(u,v)*/,int left=1,int right=N)
{
if(left==right)
{
return left;
}
int sum=tree[tree[tree1].lson].sum
+tree[tree[tree2].lson].sum
-2*tree[tree[tree3].lson].sum;//计算出这条链上在left~right中的数出现的次数
if(left<=LCA_num&&LCA_num<=MIDDLE)//如果LCA位置的数在当前的范围内就加一
{
sum++;
}
if(sum>=k)//左子树查询kth
{
return
QueryKth(k,LCA_num,
tree[tree1].lson,
tree[tree2].lson,
tree[tree3].lson,
left,MIDDLE);
}
return//右子树查询
QueryKth(k-sum,LCA_num,
tree[tree1].rson,
tree[tree2].rson,
tree[tree3].rson,
MIDDLE+1,right);
}
//一下为链式前向星部分(非主要内容,不多讲)
int head[maxN];
int edge_cnt=0;
struct Edge
{
int to,next;
}edge[maxN];
#define FOR(now) for(int i_edge=head[now];i_edge;i_edge=edge[i_edge].next)
#define TO edge[i_edge].to
void AddEdge(int form,int to)
{
edge[++edge_cnt].to=to;
edge[edge_cnt].next=head[form];
head[form]=edge_cnt;
}
//一下为倍增LCA部分(非主要内容,不多讲)
int kth_father[maxN][25];
bool visit[maxN];
int deep[maxN],father[maxN];
void DFS(int now)
{
UpData(Hash[point[now]],root[now],root[father[now]]);//在DFS的过程中把主席树建好
deep[now]=deep[father[now]]+1;
kth_father[now][0]=father[now];
REP(i,0,22)
{
kth_father[now][i+1]=kth_father[kth_father[now][i]][i];
}
FOR(now)
{
if(father[now]!=TO)
{
father[TO]=now;
DFS(TO);
}
}
}
int LCA(int x,int y)//LCA核心代码
{
if(deep[x]<deep[y])
{
swap(x,y);
}
DOW(i,22,0)
{
if(deep[kth_father[x][i]]>=deep[y])
{
x=kth_father[x][i];
}
if(x==y)
{
return x;
}
}
DOW(i,22,0)
{
if(kth_father[x][i]!=kth_father[y][i])
{
x=kth_father[x][i];
y=kth_father[y][i];
}
}
return father[x];
}
int main()
{
scanf("%d%d",&N,&M);
REP(i,1,N)
{
scanf("%d",&point[i]);
sor[i]=point[i];
}
int fa,son;
REP(i,1,N-1)
{
scanf("%d%d",&fa,&son);
AddEdge(fa,son);
AddEdge(son,fa);
}
sort(sor+1,sor+1+N);//离散化
sor[0]=-114514;
int cnt_num=0;
REP(i,1,N)
{
if(sor[i]!=sor[i-1])
{
Hash[sor[i]]=++cnt_num;
val[cnt_num]=sor[i];
}
}
N=cnt_num;
DFS(1);//DFS,建树+倍增LCA预处理
int u,v,k;
int point_LCA;
REP(i,1,M)
{
scanf("%d%d%d",&u,&v,&k);
point_LCA=LCA(u,v);//找到LCA
printf("%d\n",
val[QueryKth(k,Hash[point[point_LCA]],
root[u],root[v],root[point_LCA])]
);//直接查找kth
}
return 0;
}
「SP10628 COT - Count on a tree」的更多相关文章
- SP10628 COT - Count on a tree 主席树
Code: #include<cstdio> #include<cstring> #include<algorithm> #include<string> ...
- SPOJ - COT Count on a tree
地址:http://www.spoj.com/problems/COT/en/ 题目: COT - Count on a tree #tree You are given a tree with N ...
- SPOJ 10628 COT - Count on a tree(在树上建立主席树)(LCA)
COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...
- spoj cot: Count on a tree 主席树
10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are number ...
- spoj COT - Count on a tree (树上第K小 LCA+主席树)
链接: https://www.spoj.com/problems/COT/en/ 思路: 首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们 ...
- SPOJ 10628. SPOJ COT Count on a tree 可持久化线段树
这题是裸的主席树,每个节点建一棵主席树,再加个lca就可以了. 历尽艰辛,终于A掉了这一题,这般艰辛也显示出了打代码的不熟练. 错误:1.lca倍增的时候i和j写反了,RE了5次,实在要吸取教训 2. ...
- SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解
题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...
- spoj COT - Count on a tree(主席树 +lca,树上第K大)
您将获得一个包含N个节点的树.树节点的编号从1到Ñ.每个节点都有一个整数权重. 我们会要求您执行以下操作: uvk:询问从节点u到节点v的路径上的第k个最小权重 输入 在第一行中有两个整数Ñ和中号.( ...
- SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)
COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...
随机推荐
- 深度学习之反向传播算法(BP)代码实现
反向传播算法实战 本文仅仅是反向传播算法的实现,不涉及公式推导,如果对反向传播算法公式推导不熟悉,强烈建议查看另一篇文章神经网络之反向传播算法(BP)公式推导(超详细) 我们将实现一个 4 层的全连接 ...
- 吴裕雄 python 神经网络TensorFlow实现LeNet模型处理手写数字识别MNIST数据集
import tensorflow as tf tf.reset_default_graph() # 配置神经网络的参数 INPUT_NODE = 784 OUTPUT_NODE = 10 IMAGE ...
- 【C语言】逗号运算符的使用举例
#include<stdio.h> int main(void) { , b = , c = , y, z; y = a + b, a + c;/*由y=a+b和a+c组成的逗号表达式*/ ...
- Java入门笔记 03-面向对象(下)
介绍:除了前面介绍的关于类.对象的基本语法之外,下面继续介绍Java面向对象的特性. 一. 包装类: 从JDK 1.5以后,Java就提供了自动装箱和自动拆箱操作,即: 自动装箱:将一个基本类型的变量 ...
- 基础_04_list and tuple
一.list(列表) list是Python里的一种容器,里面可以存储多个任何类型的数据,长度也可以任意伸缩,可以像C语言中数组那样,按照索引下标获取对应的值.但数组是一个存储多个固定类型变量的连续内 ...
- HYStockChart, 股票图(包括K线图、趋势图、成交量、滚动、放大缩小等)
HYStockChart, 股票图(包括K线图.趋势图.成交量.滚动.放大缩小等) https://www.helplib.com/GitHub/article_127980git 地址 http:/ ...
- Ubuntu18 mongodb 离线安装
环境 Ubuntu 18 + mongodb 4.0.10 1.下载版本所需库 https://www.mongodb.com/download-center/community https://re ...
- windows 删除进程
win+R打开doc窗口 netstat -ano |findstr "8888" tskill 10120 结束进程
- java课极限测试
在临近国庆的9月30号补课日 碰到了惨绝人寰的java课极限测试 我从下午两点半做到晚上九点 不得不说人在烦躁的时候是真的没办法写代码的 根本不想思考也不想学习.最后的几个小时基本就是在叹息和坐着.也 ...
- 如何在JSP页面里面显示xml格式的数据
正常情况下,在jsp页面里的标签里写xml格式的数据,在浏览器里面的页面里显示出来的是乱码. 为什么会显示乱码呢?原来xml标签在jsp里会被解析为浏览器对象,因为xml最开始被设计出来是 为了写网页 ...