【解题报告】SP10628 COT-Count on a tree

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

posted @ 2022-09-22 20:12  NinT_W  阅读(19)  评论(0编辑  收藏  举报