您的位置:首页 > 其它

SPOJ COT Count on a tree 树上第k小

2017-08-04 14:59 381 查看
题目:给你一棵n个节点的树,每个节点有一个数,有m个询问,问a到b的路径上第k小的数

思路:每一棵线段数都在它的父节点的基础上修改,这样就形成了相对于根的前缀和,设a,b的最近公共祖先是c,c的父节点是d,那么答案就是a+b-c-d

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define PI acos(-1.0)
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
// 0x3f3f3f3f

const int maxn=1e5+50;
const int maxe=maxn*2;
const int maxm=maxn*30;
int arr[maxn];//原数组
int num[2*maxn],siz;//num离散化之后的数组
int root[maxn],lson[maxm],rson[maxm],cnt[maxm];//根节点,左儿子,右儿子,区间内的数出现次数的前缀和
int tot;
//LCA部分
struct node{
int u,v,w,next;
}edge[maxe];
int head[maxn],tol,total;
int order[maxn<<1],pos[maxn],dep[maxn],dis[maxn];
//oredr:dfs遍历的顺序,长度为2*n-1,下标从1开始
//pos[i]:表示点i在order中第一次出现的位置
int Log[maxn<<1],rmq[maxn<<1][20];
//结点从1开始
int fa[maxn];
void LcaInit(){
mm(head,-1);
tol=total=dep[1]=dis[1]=0;
}
void addedge(int u,int v,int w){
edge[tol].u=u;
edge[tol].v=v;
edge[tol].w=w;
edge[tol].next=head[u];
head[u]=tol++;
}
void Dfs(int u,int f){
pos[u]=++total;order[total]=u;
fa[u]=f;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v!=f){
dep[v]=dep[u]+1;
dis[v]=dis[u]+edge[i].w;
Dfs(v,u);
order[++total]=u;
}
}
}
void initLOG(){
Log[0]=-1;
for(int i=1;i<2*maxn;i++)
Log[i]=(i&(i-1))?Log[i-1]:Log[i-1]+1;
}
void initRMQ(int n) {
for(int i=1;i<=n;i++) rmq[i][0]=i;
for(int j=1;j<=Log
;j++){
int limit=n-(1<<j)+1;
for(int i=1;i<=limit;i++){
int a=rmq[i][j-1],b=rmq[i+(1<<j>>1)][j-1];
if(dep[order[a]]<dep[order[b]])
rmq[i][j]=a;
else
rmq[i][j]=b;
}
}
}
int LCA(int u, int v) {
u=pos[u];v=pos[v];
if(u>v) swap(u,v);
int t=Log[v-u+1];
int a=rmq[u][t],b=rmq[v-(1<<t)+1][t];
if(dep[order[a]]<dep[order[b]]) return order[a];
else return order[b];
}
//主席树部分
void init(){
tot=1;
root[0]=lson[0]=rson[0]=cnt[0]=0;//建一棵空树
sort(num+1,num+siz+1);//离散化
siz=unique(num+1,num+siz+1)-num-1;
}
int Hash(int x){
return lower_bound(num+1,num+siz+1,x)-num;
}
int update(int rt,int pos,int val){
int newrt=tot++,temp=newrt;
cnt[newrt]=cnt[rt]+val;
int l=1,r=siz;
while(l<r){
int mid=(l+r)/2;
if(pos<=mid){
r=mid;
lson[newrt]=tot++;rson[newrt]=rson[rt];
newrt=lson[newrt];rt=lson[rt];
}
else{
l=mid+1;
lson[newrt]=lson[rt];rson[newrt]=tot++;
newrt=rson[newrt];rt=rson[rt];
}
cnt[newrt]=cnt[rt]+val;
}
return temp;
}
int query(int a,int b,int c,int d,int k){
int l=1,r=siz;
while(l<r){
int mid=(l+r)/2;
int temp=cnt[lson[a]]+cnt[lson[b]]-cnt[lson[c]]-cnt[lson[d]];
if(temp>=k){
r=mid;
a=lson[a];
b=lson[b];
c=lson[c];
d=lson[d];
}
else{
l=mid+1;
k-=temp;
a=rson[a];
b=rson[b];
c=rson[c];
d=rson[d];
}
}
return l;
}
void build(int u,int f){
root[u]=update(root[f],Hash(arr[u]),1);
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==f) continue;
build(v,u);
}
}
int main(){

int n,m,u,v,k;
initLOG();
while(~scanf("%d%d",&n,&m)){
siz=0;
LcaInit();
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
num[++siz]=arr[i];
}
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addedge(u,v,1);
addedge(v,u,1);
}
Dfs(1,0);
initRMQ(2*n-1);
init();
build(1,0);
while(m--){
scanf("%d%d%d",&u,&v,&k);
int lca=LCA(u,v);
int ans=query(root[u],root[v],root[lca],root[fa[lca]],k);
printf("%d\n",num[ans]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: