SPOJ COTCount on a tree(树上路径第k小 主席树)
来源:互联网 发布:淘宝网首页不显示图片 编辑:程序博客网 时间:2024/06/06 17:02
题目链接
题意:
求树上A,B两点路径上第K小的数
分析:
同样是可持久化线段树,只是这一次我们用它来维护树上的信息。
我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表上。
比如说我们从一棵树的根节点进行DFS,得到根节点到各节点的距离dist[x]——这是一个根-x路径上点与根节点距离的前缀和。
利用这个前缀和,我们可以解决一些树上任意路径的问题,比如在线询问[a,b]点对的距离——答案自然是dist[a]+dist[b]-2*dist[lca(a,b)]。
同理,我们可以利用可持久化线段树来解决树上任意路径的问题。
DFS遍历整棵树,然后在每个节点上建立一棵线段树,某一棵线段树的“前一版本”是位于该节点父亲节点fa的线段树。
利用与之前类似的方法插入点权(排序离散)。那么对于询问[a,b],答案就是root[a]+root[b]-root[lca(a,b)]-root[fa[lca(a,b)]]上的第k大。
//#pragma comment(linker, "/STACK:1024000000,1024000000")#include<iostream>#include<stdio.h>#include<math.h>#include <string>#include<string.h>#include<map>#include<queue>#include<set>#include<utility>#include<vector>#include<algorithm>#include<stdlib.h>using namespace std;#define eps 1e-8#define pii pair<int,int>#define inf 0x3f3f3f3f#define rd(x) scanf("%d",&x)#define rd2(x,y) scanf("%d%d",&x,&y)#define ll long long int#define mod 1000000007#define maxn 100050#define maxm 5000005int ls[maxm],rs[maxm],sum[maxm];int tot,pos,n,m;int a[maxn],f[maxn],rt[maxn],faa[maxn];int nn,u,v,root,k;struct node{ int v,next;}edge[maxn*2];int head[maxn];void addedge(int u,int v){ edge[++tot].v=v;edge[tot].next=head[u];head[u]=tot;}void update(int &x,int pr,int l,int r,int p){//对于求第i个线段树可以理解为, x=++pos;sum[x]=sum[pr]+1; //先复制第i-1个,相同的位置公用空间,不同重新开辟 if(l==r) return; ls[x]=ls[pr];rs[x]=rs[pr]; int mid=(l+r)>>1; if(p<=mid) update(ls[x],ls[pr],l,mid,p); else update(rs[x],rs[pr],mid+1,r,p);}void build(int &x,int l,int r){ x=++pos;sum[x]=0; if(l==r) return; int mid=(l+r)/2; build(ls[x],l,mid); build(rs[x],mid+1,r);}int h(int x){//获取值x在线段树的位置 return lower_bound(f+1,f+1+nn,x)-f;}int query(int L,int R,int k,int lc,int flc,int l,int r){ if(l==r) return f[l]; int tmp=sum[ls[R]]+sum[ls[L]]-sum[ls[lc]]-sum[ls[flc]]; int mid=(l+r)>>1; if(k<=tmp) return query(ls[L],ls[R],k,ls[lc],ls[flc],l,mid); else return query(rs[L],rs[R],k-tmp,rs[lc],rs[flc],mid+1,r);}int rmq[2*maxn];//求公共祖先在线算法struct ST{ int mm[2*maxn]; int dp[2*maxn][20]; void init(int n){ mm[0]=-1; for(int i=1;i<=n;i++){ mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; dp[i][0]=i; } for(int j=1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]? dp[i][j-1]:dp[i+(1<<(j-1))][j-1]; } int query(int a,int b){ if(a>b) swap(a,b); int k=mm[b-a+1]; return rmq[dp[a][k]]<=rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k]; }}st;int F[maxn*2],P[maxn],cnt;void dfs(int x,int fa,int deep){ faa[x]=fa; F[++cnt]=x;rmq[cnt]=deep;P[x]=cnt; update(rt[x],rt[fa],1,nn,h(a[x])); for(int i=head[x];i!=-1;i=edge[i].next){ if(edge[i].v==fa) continue; dfs(edge[i].v,x,deep+1); F[++cnt]=x;rmq[cnt]=deep; }}int query_lca(int u,int v){ return F[st.query(P[u],P[v])];}int main(){ rd2(n,m); for(int i=1;i<=n;i++) { rd(a[i]);f[i]=a[i]; } sort(f+1,f+1+n); nn=unique(f+1,f+1+n)-f-1;//离散化线段树 memset(head,-1,sizeof(head)); for(int i=1;i<n;i++){ rd2(u,v); addedge(u,v); addedge(v,u); } pos=tot=cnt=0; build(rt[0],1,nn); dfs(1,0,0);//构建线段树组,根据父子关系 st.init(2*n-1); for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&k); int lc=query_lca(u,v); printf("%d\n",query(rt[u],rt[v],k,rt[lc],rt[faa[lc]],1,nn)); } return 0;}
0 0
- SPOJ COTCount on a tree(树上路径第k小 主席树)
- SPOJ COTCount on a tree 树上第k大(主席树)
- 2588: Spoj 10628. Count on a tree (主席树,树上路径第K大值)
- SPOJ 10628. Count on a tree (树上第k大,LCA+主席树)
- SPOJ COT Count on a tree 树上第k小
- 【BZOJ 2588】Count on a tree 【树上路径第K大】【LCA+主席树】
- bzoj2588 Count on a tree(树上建主席树求路径第k大)
- SPOJ Count on a tree(树上第K大)
- 【BZOJ 2588】 Spoj 10628. Count on a tree|树上K大|树链剖分|主席树
- SPOJ COT Count on a tree (树上k大 主席树模板)
- Spoj 10628. Count on a tree 树上主席树
- SPOJ Count on a tree 树上第k大。
- bzoj 2588: Spoj 10628. Count on a tree(树上主席树)
- SPOJ COT 主席树+LCA(树上第k大)
- SPOJ Count on a tree(lca+主席树,树上主席树,好题)
- 【BZOJ 2588】Spoj 10628. Count on a tree 主席树+树上差分
- BZOJ BZOJ 2588: Spoj 10628. Count on a tree 树上主席树
- [BZOJ2588][Spoj10628]Count on a tree(树上主席树)
- iOS开发--TDD的iOS开发初步以及Kiwi使用入门
- 清除浮动
- 最小表示法--让你速度gank序列
- 第19章 事务
- MFC自绘-WzdButton按钮类
- SPOJ COTCount on a tree(树上路径第k小 主席树)
- HDU 2602:Bone Collector【01背包】
- Word2Vec之Deep Learning in NLP (一)词向量和语言模型
- PHP生成PDF文件
- 帮Facebook把用户做到7亿 他只做了三件事
- Android Studio奇技淫巧一览 大幅度提升工作效率
- Mr. Process的一生-Linux内核的社会视角 (1) 调度
- TextView和EditText的显示
- 检测版本更新