SP10628 COT
双倍经验,两个题一样的啦
简要题意
给出一颗n个节点的树,每个节点都有一个权值,求u到v的第k小权值
其实就是树上的区间第k小
主席树+树上差分
先想一想序列上的怎么做
当然就是主席树啦(不会的点这里)
然后想一想树上怎么搞
可以进行树上差分
一般分为两种:点/边上的差分
点上的:u到根+v到根-LCA到根-LCA的爹到根(指路径上点的权值)
边上的:u到根+v到根-2*(LCA到根)(指路径上边的权值)
这里的LCA我用树剖来求QWQ
而在这道题里明显是针对点的树上差分
和普通的主席树差不多啦,就是多了几个参数(LCA和它爹)
AC 代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100010;
inline int read()
{
int w=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
{
f=-1;
}
ch=getchar();
}
while(ch>='0' && ch<='9')
{
w=(w<<3)+(w<<1)+(ch^48);
ch=getchar();
}
return w*f;
}
int cnt,num;
int n,m,tot;
int fa[maxn];
int id[maxn];
int val[maxn];
int fub[maxn];
int siz[maxn];
int head[maxn];
int deep[maxn];
int top[maxn];
int root[maxn];
int max_son[maxn];
struct s_t
{
int ls;
int rs;
int sum;
}t[maxn<<5];
struct edge
{
int to;
int val;
int next;
}e[maxn*2];
void add(int x,int y)
{
tot++;
e[tot].to=y;
e[tot].next=head[x];
head[x]=tot;
}
void update(int &p,int las,int l,int r,int k) //主席树板子
{
p=++cnt;
t[p]=t[las];
if(l==r)
{
t[p].sum++;
return ;
}
int mid=(l+r)>>1;
if(k<=mid)
{
update(t[p].ls,t[las].ls,l,mid,k);
}
else
{
update(t[p].rs,t[las].rs,mid+1,r,k);
}
t[p].sum=t[t[p].ls].sum+t[t[p].rs].sum;
}
int query(int p,int las,int lca,int fa_lca,int l,int r,int k)
{
if(l==r)
{
return l;
}
int mid=(l+r)>>1;
int sum=t[t[p].ls].sum+t[t[las].ls].sum-t[t[lca].ls].sum-t[t[fa_lca].ls].sum;
if(k<=sum)
{
return query(t[p].ls,t[las].ls,t[lca].ls,t[fa_lca].ls,l,mid,k);
}
else
{
return query(t[p].rs,t[las].rs,t[lca].rs,t[fa_lca].rs,mid+1,r,k-sum);
}
}
void dfs_first(int x,int fath) //树剖求LCA
{
update(root[x],root[fath],1,num,val[x]);
fa[x]=fath;
deep[x]=deep[fath]+1;
siz[x]=1;
for(int i=head[x];i;i=e[i].next)
{
int to=e[i].to;
if(to==fath)
{
continue;
}
dfs_first(to,x);
siz[x]+=siz[to];
if(siz[to]>siz[max_son[x]])
{
max_son[x]=to;
}
}
}
void dfs_second(int x,int t)
{
tot++;
id[x]=tot;
top[x]=t;
e[tot].val=val[x];
if(max_son[x]==0)
{
return ;
}
dfs_second(max_son[x],top[x]);
for(int i=head[x];i;i=e[i].next)
{
int to=e[i].to;
if(to!=fa[x] && to!=max_son[x])
{
dfs_second(to,to);
}
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
{
swap(x,y);
}
x=fa[top[x]];
}
return deep[x]<deep[y] ? x : y;
}
int main()
{
freopen("qwq.in","r",stdin);
freopen("qwq.out","w",stdout);
n=read();
m=read();
for(int i=1;i<=n;i++)
{
fub[i]=val[i]=read();
}
sort(fub+1,fub+n+1); //离散化
num=unique(fub+1,fub+n+1)-fub-1;
for(int i=1;i<=n;i++)
{
val[i]=lower_bound(fub+1,fub+num+1,val[i])-fub;
}
for(int i=1;i<n;i++)
{
int u=read();
int v=read();
add(u,v);
add(v,u);
}
tot=0;
dfs_first(1,0);
tot=0;
dfs_second(1,1);
for(int i=1;i<=m;i++)
{
int u=read();
int v=read();
int k=read();
int lca=LCA(u,v);
cout<<fub[query(root[u],root[v],root[lca],root[fa[lca]],1,num,k)]<<endl;
}
fclose(stdin);
fclose(stdout);
return 0;
}
真是道大水题呢QWQ