SPOJ_10628_Count_on_a_Tree(主席树+Tarjan)

描述



http://www.spoj.com/problems/COT/

给出一棵n个节点的树,树上每一个节点有权值.m次询问,求书上u,v路径中第k小的权值.

分析



POJ_2104_Kth(主席树)

现在是把原来的问题搬到树上去了.首先我们肯定要求lca,新学了Tarjan的离线算法.

每一个点建立到根节点的主席树,这样最后的结果就是u+v-2*lca,如果lca在所要求的区间内,还要再加上lca.(或者u+v-lca-p[lca]).

自己理解一下吧...挺简单的.

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <vector>
 4 using namespace std;
 5
 6 const int maxn=100000+5;
 7 int n,m,cnt,num;
 8 int a[maxn],id[maxn],b[maxn],head[maxn],p[maxn],f[maxn],root[maxn];
 9 bool vis[maxn];
10 struct edge{
11     int to,next;
12     edge(){}
13     edge(int a,int b):to(a),next(b){}
14 }g[maxn<<1];
15 struct Qry{
16     int u,v,k,lca;
17     Qry(){}
18     Qry(int a,int b,int c,int d):u(a),v(b),k(c),lca(d){}
19 }Q[maxn];
20 struct node{ int l,r,s; }t[maxn*20];
21 struct qry{
22     int v,id;
23     qry(){}
24     qry(int a,int b):v(a),id(b){}
25 };
26 vector <qry> q[maxn];
27
28 inline int find(int x){ return x==f[x]?x:f[x]=find(f[x]); }
29 void add_edge(int u,int v){
30     g[++cnt]=edge(v,head[u]); head[u]=cnt;
31     g[++cnt]=edge(u,head[v]); head[v]=cnt;
32 }
33 void update(int l,int r,int &pos,int d){
34     t[++num]=t[pos]; pos=num; t[pos].s++;
35     if(l==r) return;
36     int mid=l+(r-l)/2;
37     if(d<=mid) update(l,mid,t[pos].l,d);
38     else update(mid+1,r,t[pos].r,d);
39 }
40 bool cmp(int x,int y){ return a[x]<a[y]; }
41 void dfs(int u){
42     f[u]=u; root[u]=root[p[u]]; update(1,n,root[u],b[u]);
43     for(int i=head[u];i;i=g[i].next){
44         if(g[i].to!=p[u]){
45             p[g[i].to]=u;
46             dfs(g[i].to);
47             f[g[i].to]=u;
48         }
49     }
50     vis[u]=true;
51     int size=q[u].size();
52     for(int i=0;i<size;i++) if(vis[q[u][i].v]) Q[q[u][i].id].lca=find(q[u][i].v);
53 }
54 void init(){
55     scanf("%d%d",&n,&m);
56     for(int i=1;i<=n;i++) scanf("%d",&a[i]), id[i]=i;
57     sort(id+1,id+n+1,cmp);
58     for(int i=1;i<=n;i++) b[id[i]]=i;
59     for(int i=1;i<n;i++){
60         int u,v;
61         scanf("%d%d",&u,&v);
62         add_edge(u,v);
63     }
64     for(int i=1;i<=m;i++){
65         scanf("%d%d%d",&Q[i].u,&Q[i].v,&Q[i].k);
66         q[Q[i].u].push_back(qry(Q[i].v,i)); q[Q[i].v].push_back(qry(Q[i].u,i));
67     }
68 }
69 int query(int l,int r,int x,int y,int ra,int a,int k){
70     if(l==r) return l;
71     int mid=l+(r-l)/2;
72     int s=t[t[x].l].s+t[t[y].l].s-2*t[t[ra].l].s;
73     if(b[a]>=l&&b[a]<=mid) s++;
74     if(k<=s) return query(l,mid,t[x].l,t[y].l,t[ra].l,a,k);
75     else return query(mid+1,r,t[x].r,t[y].r,t[ra].r,a,k-s);
76 }
77 void solve(){
78     dfs(1);
79     for(int i=1;i<=m;i++){
80         if(Q[i].u==Q[i].v){ printf("%d\n",a[Q[i].u]); continue; }
81         printf("%d\n",a[id[query(1,n,root[Q[i].u],root[Q[i].v],root[Q[i].lca],Q[i].lca,Q[i].k)]]);
82     }
83 }
84 int main(){
85     init();
86     solve();
87     return 0;
88 }

时间: 2024-11-09 03:57:14

SPOJ_10628_Count_on_a_Tree(主席树+Tarjan)的相关文章

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 N.Each node has an integer weight. We will ask you to perform the following operation: u v k : ask for the kth minimum weight on the path from node u 

【BZOJ 3772】精神污染 主席树+欧拉序

这道题的内存-------真·精神污染---.. 这道题的思路很明了,我们就是要找每一个路径包含了多少其他路径那么就是找,有多少路径的左右端点都在这条路径上,对于每一条路径,我们随便选定一个端点作为第一关键字,另一个作为第二关键字,于是就有了两维限制,按照主席树的一般思路,我们把建树顺序作为一维,然后在里面维护另一维,那么我们在外面限制第一关键字,就是在树上建主席树,查询减LCA,在里面的话我们把每个点作为第一关键字对应的第二关键字,放入主席树,而主席树维护的是欧拉序区间,所以我们每次查询只用查

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

[bzoj3932][CQOI2015]任务查询系统-题解[主席树][权值线段树]

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

BZOJ_3207_花神的嘲讽计划1_(Hash+主席树)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3207 给出一个长度为\(n\)的串,以及\(m\)个长度为\(k\)的串,求每个长度为\(k\)的串在原串\([x,y]\)区间是否出现过. 分析 这道题要求对比长度为\(k\)的串,于是我们把这些串的Hash值都算出来,问题就转化成了求\([x,y]\)的区间中是否出现过某Hash值. 求区间中某一个值出现了多少次,可以用主席树. p.s. 1.学习了主席树指针的写法,比数组慢好多啊...

[主席树]ZOJ3888 Twelves Monkeys

题意:有n年,其中m年可以乘时光机回到过去,q个询问 下面m行,x,y 表示可以在y年穿越回x年, 保证y>x 下面q个询问, 每个询问有个年份k 问的是k年前面 有多少年可以通过一种以上($\ge 2$)方法穿越回去的, 其中时光机只能用一次 比如案例 9 3 3 9 1 6 1 4 1 6 7 2 如图 对于询问 6这一年:1.穿越回第1年  2.等时间过呀过呀过到第9年,再穿越回第1年 那么第1年就有两种方法可以穿越回去, 同理, 2.3.4年也有同样两种方法(回到1再等时间过呀过 过到2

POJ2104主席树模板题

完成新成就——B站上看了算法https://www.bilibili.com/video/av4619406/?from=search&seid=17909472848554781180#page=2 K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 60158   Accepted: 21054 Case Time Limit: 2000MS Description You are working

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由器老化,在这些