首页 > 其他 > 详细

luogu P5311 [Ynoi2011]成都七中

时间:2020-07-11 18:40:57      阅读:44      评论:0      收藏:0      [点我收藏+]

首先考虑判断两个点 \(a,b\) 在一个询问 \((l,r,x)\) 下连通:\(path(a,b)\) 上的点的编号都在 \(l \sim r\) 之间,可以用倍增预处理。

对原树建立点分树。对于每个询问 \((l,r,x)\),我们考虑找到这样一个点:

  1. 这个点是 \(x\) 在点分树上的祖先
  2. 这个点与 \(x\) 连通
  3. 满足以上两个条件的情况下,要求这个点的深度尽可能小

设找到的这个点为 \(y\)。那么所有与 \(x\) 连通的点都必然在 \(y\) 的子树(点分树)内。我们把这个询问离线下来插进 \(y\) 里。然后这个询问就和 \(x\) 没有关系了。

然后对于点分树上每个点 \(x\),对于它的子树上的一个点 \(p\),设 \(path(x,p)\) 上编号最大的点为 \(mx\),编号最小的点为 \(mn\),那么他们连通的条件就是 \(mn\geq l\) 且 \(mx\leq r\)。那么和我们像 HH的项链 这题一样处理二维偏序和颜色种类就好了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<ctime>

using namespace std;

const int N=100009;
int head[N],cnt,n,q,ans[N],F[N],root,col[N];
struct Edge
{
	int nxt,to;
}g[N*2];
struct Tree
{
	int head[N],cnt,del[N],siz[N];
	int dep[N],f[N][30],fmin[N][30],fmax[N][30];
	
	struct Edge
	{
		int nxt,to;
	}g[N*2];
	
	void add(int from,int to)
	{
		g[++cnt].nxt=head[from];
		g[cnt].to=to;
		head[from]=cnt;
	}
	
	void dfs(int x,int fa)
	{
		siz[x]=1;
		for (int i=head[x];i;i=g[i].nxt)
		{
			int v=g[i].to;
			if(v==fa||del[v])
				continue;
			dfs(v,x);
			siz[x]+=siz[v];
		}
	}
	
	int Get_Weight(int x)
	{
		dfs(x,-1);
		int k=siz[x]/2,fa=-1;
		while(1)
		{
			int tmp=0;
			for (int i=head[x];i;i=g[i].nxt)
			{
				int v=g[i].to;
				if(v==fa||del[v])
					continue;
				if(siz[tmp]<siz[v])
					tmp=v;
			}
			if(siz[tmp]<=k)
				return x;
			fa=x,x=tmp;
		}
	}
	
	void DFS(int x,int fa)
	{
		fmin[x][0]=fmax[x][0]=x;
		for (int i=head[x];i;i=g[i].nxt)
		{
			int v=g[i].to;
			if(v==fa)
				continue;
			dep[v]=dep[x]+1;
			f[v][0]=x;
			DFS(v,x);
		}
	}
	
	pair<int,int> Get_Min_Max(int x,int y)
	{
		int Min=1<<30,Max=0;
		if(dep[x]!=dep[y])
		{
			if(dep[x]<dep[y])
				swap(x,y);
			int k=dep[x]-dep[y];
			for (int i=20;i>=0;i--)
				if(k>=1<<i)
					Min=min(Min,fmin[x][i]),
					Max=max(Max,fmax[x][i]),
					x=f[x][i],k-=1<<i;
		}
		if(x==y)
			return make_pair(min(Min,x),max(Max,x));
		for (int i=20;i>=0;i--)
			if(f[x][i]!=f[y][i])
				Min=min(Min,min(fmin[y][i],fmin[x][i])),
				Max=max(Max,max(fmax[y][i],fmax[x][i])),
				x=f[x][i],y=f[y][i];
		Min=min(Min,min(fmin[y][0],fmin[x][0]));
		Max=max(Max,max(fmax[y][0],fmax[x][0]));
		return make_pair(min(Min,f[x][0]),max(f[x][0],Max));
	}
	
	void work()
	{
		memset(fmin,0x3f,sizeof(fmin));
		add(0,1);
		DFS(0,-1);
		for (int j=1;j<=20;j++)
			for (int i=1;i<=n;i++)
				f[i][j]=f[f[i][j-1]][j-1],
				fmin[i][j]=min(fmin[i][j-1],fmin[f[i][j-1]][j-1]),
				fmax[i][j]=max(fmax[i][j-1],fmax[f[i][j-1]][j-1]);
	}
}T;
struct Question
{
	int id,l,r;
	bool operator < (const Question A)const
	{
		return r<A.r;
	}
};
struct BIT
{
	#define MaxN 100000
	int c[N];
	
	int lowbit(int x)
	{
		return x&-x;
	}
	
	void Modify(int x,int k)
	{
		while(x<=MaxN)
			c[x]+=k,x+=lowbit(x);
	}
	
	int Query(int x)
	{
		int ans=0;
		while(x)
			ans+=c[x],x-=lowbit(x);
		return ans;
	}
}A;
struct Bin
{
	int l,r,col;
	bool operator < (const Bin A)const
	{
		return r<A.r;
	}
};
Bin bin[N];
vector <Question> b[N];

void add(int from,int to)
{
	g[++cnt].nxt=head[from];
	g[cnt].to=to;
	head[from]=cnt;
}

void init()
{
	scanf("%d %d",&n,&q);
	for (int i=1;i<=n;i++)
		scanf("%d",&col[i]);
	for (int i=1,x,y;i<n;i++)
		scanf("%d %d",&x,&y),
		T.add(x,y),T.add(y,x);
	T.work();
}

void build(int x,int fa)
{
	int w=T.Get_Weight(x);
	T.del[w]=1;
	if(fa!=-1)
		add(w,fa),add(fa,w),F[w]=fa;
	else
		root=w;
	for (int i=T.head[w];i;i=T.g[i].nxt)
	{
		int v=T.g[i].to;
		if(T.del[v]) continue;
		build(v,w);
	}
}

int Cnt;

void DFS(int x,int fa,int X)
{
	pair<int,int> G=T.Get_Min_Max(X,x);
	bin[++Cnt]=(Bin){G.first,G.second,col[x]};
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		DFS(v,x,X);
	}
}

int Maxc[N];

void dfs(int x,int fa)
{
	Cnt=0,DFS(x,fa,x);
	int now=1;
	sort(b[x].begin(),b[x].end());
	sort(bin+1,bin+1+Cnt);
	for (int i=0;i<b[x].size();i++)
	{
		Question v=b[x][i];
		while(bin[now].r<=v.r&&now<=Cnt)
		{
			if(Maxc[bin[now].col]==0)
				A.Modify(bin[now].l,1),
				Maxc[bin[now].col]=bin[now].l;
			else if(Maxc[bin[now].col]<bin[now].l)
				A.Modify(bin[now].l,1),
				A.Modify(Maxc[bin[now].col],-1),
				Maxc[bin[now].col]=bin[now].l;
			now++;
		}
//		printf("%d %d\n",v.r,v.l-1);
		ans[v.id]=A.Query(v.r)-A.Query(v.l-1);
	}
	for (int i=1;i<=Cnt;i++)
		if(Maxc[bin[i].col]!=0)
			A.Modify(Maxc[bin[i].col],-1),
			Maxc[bin[i].col]=0;
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		dfs(v,x);
	}
}

void print(int x,int fa)
{
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		printf("%d %d\n",x,v);
		print(v,x);
	} 
}

void work()
{
	build(1,-1);
//	print(root,-1);
	/*srand(time(0));
	puts("wyj!!!");
	for (int i=1;i<=10;i++)
	{
		int x=rand()%n+1,y=rand()%n+1;
		if(x>y) swap(x,y);
		pair<int,int> G=T.Get_Min_Max(x,y);
		printf("%d %d %d %d\n",x,y,G.first,G.second);
	}*/
//	pair<int,int> G=T.Get_Min_Max(5,10);
//	printf("%d %d\n",G.first,G.second);
	for (int i=1;i<=q;i++)
	{
		int x,y,z;
		scanf("%d %d %d",&x,&y,&z);
		int pos=z;
		for (int j=F[z];j;j=F[j])
		{
			pair<int,int> G=T.Get_Min_Max(j,z);
			if(G.first>=x&&G.second<=y) pos=j;
		}
		b[pos].push_back((Question){i,x,y});
	}
	dfs(root,-1);
	for (int i=1;i<=q;i++)
		printf("%d\n",ans[i]);
}

int main()
{
	init();
	work();
	return 0;
}

luogu P5311 [Ynoi2011]成都七中

原文:https://www.cnblogs.com/With-penguin/p/13284442.html

踩
(0)
赞
(0)
   
举报
评论 一句话评论(0)
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!