【XSY1642】Another Boring Problem 树上莫队

题目大意

  给你一棵(n)个点的树,每个点有一个颜色(c_i),每次给你(x,y,k),求从(x)(y)的路径上出现次数第(k)多的颜色的出现次数

  (n,qleq 100000)

题解

  树上莫队

  先求出这棵树的dfs序(括号序列),记录每个点第一次出现的位置(st_x)和最后一次出现的位置(ed_x)

  

  若每次询问的(x,y)中有一个是另一个的祖先(设(x)(y)的祖先),那么就可以视为询问区间([st_x,st_y])

  可是一些不在这条链上的点会出现两次,我们把出现两次的点视为没出现过。

  

  否则就视为询问([ed_x,st_y])(设(st_x<st_y))。但是(lca)处没有被统计到。直接暴力把(lca)处的贡献统计一下就可以了。

  

  其他的和普通莫队一样了。

  时间复杂度:(O((n+q)sqrt{n}))

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<list>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
list<int> l[200010];
int f[200010][20];
int st[500010];
int ed[500010];
int ti;
int w[1000010];
int c[500010];
int a[500010];
int e[500010];
int d[500010];
int m;
void dfs(int x,int fa,int dep)
{
	st[x]=++ti;
	w[ti]=x;
	d[x]=dep;
	f[x][0]=fa;
	int i;
	for(i=1;i<=19;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for(auto v:l[x])
		if(v!=fa)
			dfs(v,x,dep+1);
	ed[x]=++ti;
	w[ti]=x;
}
int getlca(int x,int y)
{
	if(d[x]<d[y])
		swap(x,y);
	int i;
	for(i=19;i>=0;i--)
		if(d[f[x][i]]>=d[y])
			x=f[x][i];
	if(x==y)
		return x;
	for(i=19;i>=0;i--)
		if(f[x][i]!=f[y][i])
		{
			x=f[x][i];
			y=f[y][i];
		}
	return f[x][0];
}
int bl;
int ans[500010];
int a1[500010];
int a2[500010];
int g[500010];
int n,q;
struct p
{
	int l,r;
	int k;
	int id;
	int b;
	int c;
	p()
	{
		c=b=l=r=k=id=0;
	}
};
p b[500010];
int cmp(p a,p b)
{
	if(a.b!=b.b)
		return a.b<b.b;
	return a.r<b.r;
}
int block[500010];
int *c1[500010];
int *t[500010];
void add(int x)
{
	a1[x]++;
//	x=(x+bl-1)/bl;
//	a2[x]++;
	(*c1[x])++;
}
void del(int x)
{
	a1[x]--;
//	x=(x+bl-1)/bl;
//	a2[x]--;
	(*c1[x])--;
}
void change(int x)
{
//	int &b=g[c[x]];
	int &b=*t[x];
	if(a[x])
	{
		a[x]=0;
//		del(b);
		a1[b]--;
		(*c1[b])--;
		b--;
//		add(b);
		a1[b]++;
		(*c1[b])++;
	}
	else
	{
		a[x]=1;
//		del(b);
		a1[b]--;
		(*c1[b])--;
		b++;
//		add(b);
		a1[b]++;
		(*c1[b])++;
	}
}
int num;
int query(int k)
{
	int i,j;
	for(i=num;i>=1;i--)
		if(a2[i]>=k)
		{
			j=min(n,i*bl);
			for(;;j--)
				if(a1[j]>=k)
					return j;
				else
					k-=a1[j];
		}
		else
			k-=a2[i];
	return 0;
}
void rd(int &s)
{
	int c;
	while((c=getchar())<'0'||c>'9');
	s=c-'0';
	while((c=getchar())>='0'&&c<='9')
		s=s*10+c-'0';
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
//	scanf("%d%d",&n,&q);
	rd(n);
	rd(q);
	bl=500;
	int m=0;
	int i;
	for(i=1;i<=n;i++)
	{
//		scanf("%d",&c[i]);
		rd(c[i]);
		e[++m]=c[i];
	}
	sort(e+1,e+m+1);
	m=unique(e+1,e+m+1)-e-1;
	for(i=1;i<=n;i++)
		c[i]=lower_bound(e+1,e+m+1,c[i])-e;
	int x,y;
	for(i=1;i<n;i++)
	{
//		scanf("%d%d",&x,&y);
		rd(x);
		rd(y);
		l[x].push_back(y);
		l[y].push_back(x);
	}
	dfs(1,0,1);
	num=(n+bl-1)/bl;
	for(i=0;i<=n;i++)
	{
		c1[i]=&a2[(i+bl-1)/bl];
		t[i]=&g[c[i]];
	}
	for(i=1;i<=q;i++)
	{
//		scanf("%d%d%d",&x,&y,&b[i].k);
		rd(x);
		rd(y);
		rd(b[i].k);
		b[i].id=i;
		if(st[x]<=st[y]&&ed[x]>=ed[y])
		{
			b[i].l=st[x];
			b[i].r=st[y];
			b[i].c=0;
		}
		else if(st[y]<=st[x]&&ed[y]>=ed[x])
		{
			b[i].l=st[y];
			b[i].r=st[x];
			b[i].c=0;
		}
		else
		{
			if(st[x]>st[y])
				swap(x,y);
			b[i].l=ed[x];
			b[i].r=st[y];
			b[i].c=1;
		}
		b[i].b=(b[i].l+bl-1)/bl;
	}
	sort(b+1,b+q+1,cmp);
	int l=1,r=0;
	for(i=1;i<=q;i++)
	{
		while(r<b[i].r)
			change(w[++r]);
		while(l>b[i].l)
			change(w[--l]);
		while(r>b[i].r)
			change(w[r--]);
		while(l<b[i].l)
			change(w[l++]);
		if(b[i].c)
		{
			int lca=getlca(w[b[i].l],w[b[i].r]);
			change(lca);
			ans[b[i].id]=query(b[i].k);
			change(lca);
		}
		else
			ans[b[i].id]=query(b[i].k);
	}
	for(i=1;i<=q;i++)
		printf("%d
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/ywwyww/p/8511286.html