洛谷P3242接水果

Posted stoorz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P3242接水果相关的知识,希望对你有一定的参考价值。

题目

题目链接:https://www.luogu.com.cn/problem/P3242
风见幽香非常喜欢玩一个叫做 osu! 的游戏,其中她最喜欢玩的模式就是接水果。由于她已经 DT FC 了 The big black,她觉得这个游戏太简单了,于是发明了一个更加难的版本。
首先有一个地图,是一棵由 \\(n\\) 个顶点,\\(n-1\\) 条边组成的树。
这颗树上有 \\(p\\) 个盘子,每个盘子实际上是一条路径,并且每个盘子还有一个权值。第 \\(i\\) 个盘子就是顶点 \\(a_i\\) 到顶点 \\(b_i\\) 的路径(由于是树,所以从 \\(a_i\\)\\(b_i\\) 的路径是唯一的),权值为 \\(c_i\\)
接下来依次会有 \\(q\\) 个水果掉下来,每个水果本质上也是一条路径,第 \\(i\\) 个水果是从顶点 \\(u_i\\) 到顶点 \\(v_i\\) 的路径。
幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径。这里规定:从 \\(a\\)\\(b\\) 的路径与从 \\(b\\)\\(a\\) 的路径是同一条路径。
当然为了提高难度,对于第 \\(i\\) 个水果,你需要选择能接住它的所有盘子中,权值第 \\(k_i\\) 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
\\(n,p,q\\leq 4\\times 10^4\\)

思路

\\(L_x=\\text{dfn}_x,R_x=\\text{dfn}_x+\\text{siz}_x-1\\)
假设路径 \\(a\\to b\\) 包含了路径 \\(c\\to d\\)(其中 \\(L_a<L_b,L_c<L_d\\)),考虑他们之间的关系:

  • 如果 \\(a\\) 不是 \\(b\\) 的祖先,那么 \\(c\\) 一定在 \\(a\\) 的子树内,\\(d\\) 一定在 \\(c\\) 的子树内。
    \\(L_a\\leq L_c\\leq R_a,L_b\\leq L_d\\leq R_b\\)
  • 如果 \\(a\\)\\(b\\) 的祖先,记 \\(p\\)\\(a\\to b\\) 路径上 \\(a\\) 的儿子,那么 \\(c\\) 一定不在 \\(p\\) 的子树内,\\(d\\) 一定在 \\(c\\) 的子树内。
    \\(1\\leq L_c<L_p,L_b\\leq L_d\\leq R_b\\)\\(R_p<L_c\\leq n,L_b\\leq L_d\\leq R_b\\)

把不等关系放在一个平面上,那么也就是给出若干个矩形以及若干个点,需要求每一个点被覆盖的矩形中,权值第 \\(k\\) 小的那个矩形。
显然需要整体二分或者树套树。我选择整体二分。剩余的就是板子了。扫描线 + 树状数组即可。
时间复杂度 \\(O(m\\log^2 n)\\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=160010,LG=15;
int n,m,Q,tot,head[N],L[N],R[N],num[N],rk[N],ans[N],dep[N],f[N][LG+1];

struct edge
{
	int next,to;
}e[N];

void add(int from,int to)
{
	e[++tot]=(edge){head[from],to};
	head[from]=tot;
}

struct node1
{
	int x,l,r,v,id;
}a[N],c[N];

struct node2
{
	int x,y,k,id;
}b[N],d[N];

bool cmp1(node1 x,node1 y)
{
	return num[x.id]<num[y.id];
}

bool cmp2(node1 x,node1 y)
{
	return x.x<y.x;
}

bool cmp3(node2 x,node2 y)
{
	return x.x<y.x;
}

void dfs(int x,int fa)
{
	L[x]=++tot; dep[x]=dep[fa]+1; f[x][0]=fa;
	for (int i=1;i<=LG;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa) dfs(v,x);
	}
	R[x]=tot;
}

int findson(int x,int y)
{
	for (int i=LG;i>=0;i--)
		if (dep[f[y][i]]>dep[x]) y=f[y][i];
	return y;
}

void work(int x,int y,int xx,int yy,int id)
{
	a[++tot]=(node1){x,y,yy,1,id};
	a[++tot]=(node1){xx+1,y,yy,-1,id};
}

struct BIT
{
	int c[N];
	
	void add(int x,int v)
	{
		for (int i=x;i<=n;i+=i&-i)
			c[i]+=v;
	}
	
	int query(int x)
	{
		int res=0;
		for (int i=x;i;i-=i&-i)
			res+=c[i];
		return res;
	}
}bit;

void solve(int ql,int qr,int l,int r,int pl,int pr)
{
	if (l==r)
	{
		for (int i=ql;i<=qr;i++)
			ans[b[i].id]=num[a[pl].id];
		return;
	}
	int mid=(l+r)>>1,qql=ql-1,qqr=qr+1,ppl=pl-1,ppr=pr+1,j=pl;
	for (int i=ql;i<=qr;i++)
	{
		for (;j<=pr && a[j].x<=b[i].x;j++)
			if (rk[a[j].id]<=mid && a[j].l<=a[j].r+1)
				bit.add(a[j].l,a[j].v),bit.add(a[j].r+1,-a[j].v);
		int k=bit.query(b[i].y);
		if (k>=b[i].k) d[++qql]=b[i];
			else d[--qqr]=b[i],d[qqr].k-=k;
	}
	for (;j<=pr;j++)
		if (rk[a[j].id]<=mid && a[j].l<=a[j].r)
			bit.add(a[j].l,a[j].v),bit.add(a[j].r+1,-a[j].v);
	for (int i=pl;i<=pr;i++)
		if (rk[a[i].id]<=mid) c[++ppl]=a[i];
			else c[--ppr]=a[i];
	for (int i=ql;i<=qql;i++) b[i]=d[i];
	for (int i=qr;i>=qqr;i--) b[i]=d[qr-i+qqr];
	for (int i=pl;i<=ppl;i++) a[i]=c[i];
	for (int i=pr;i>=ppr;i--) a[i]=c[pr-i+ppr];
	solve(ql,qql,l,mid,pl,ppl);
	solve(qqr,qr,mid+1,r,ppr,pr); 
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d%d%d",&n,&m,&Q);
	for (int i=1,x,y;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y); add(y,x);
	}
	tot=0; dfs(1,0); tot=0;
	for (int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&num[i]);
		if (L[x]>L[y]) swap(x,y);
		if (R[x]>=R[y])
		{
			int p=findson(x,y);
			work(1,L[y],L[p]-1,R[y],i); work(L[y],R[p]+1,R[y],n,i);
		}
		else work(L[x],L[y],R[x],R[y],i);
	}
	sort(a+1,a+1+tot,cmp1);
	for (int i=1,j=1;i<=tot;i++)
		if (!rk[a[i].id]) rk[a[i].id]=j++;
	sort(a+1,a+1+tot,cmp2);
	for (int i=1;i<=Q;i++)
	{
		scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].k);
		b[i].id=i; b[i].x=L[b[i].x]; b[i].y=L[b[i].y];
		if (b[i].x>b[i].y) swap(b[i].x,b[i].y);
	}
	sort(b+1,b+1+Q,cmp3);
	solve(1,Q,1,m,1,tot);
	for (int i=1;i<=Q;i++)
		cout<<ans[i]<<"\\n";
	return 0;
}

以上是关于洛谷P3242接水果的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4009 & 洛谷3242 & LOJ2113:[HNOI2015]接水果——题解

BZOJ4009: [HNOI2015]接水果

BZOJ 4009: [HNOI2015]接水果

使用Python开发一个超级简单的接水果小游戏,零基础也可以学会

BZOJ4009 HNOI2015 接水果

Python开发接水果小游戏