Codeforces526G Spiders Evil Plan

版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/88825177

Problem

Codeforces

Solution

我们可以先考虑怎么解决单组询问。可以把 x x 提做根,然后每次贪心选贡献最大的叶子即可。注意到叶子被选作的贡献是可以确定的,因为选叶子的顺序是固定的,而这个恰好对应这这棵树的长链剖分,选某个叶子的贡献就是它的长链的长度。那么我们就得到了一个优秀的 O ( n 2 log n + m ) O(n^2\log n+m) 算法啦!

这个算法的瓶颈在于对每个询问的 x x 都要换根建树,注意到选的叶子中必定至少有直径的一端,那么我们就可以对这两个端点建树,每次询问选择 2 y 1 2y-1 个叶子。
为了强制包含 x x ,有两种情况,一种是不选最短的叶子,另一种是在 x x 的某个 l c a lca 处转角。第一种情况比较好解决。第二种情况就是要求下式:

max i 2 y 1 { d i s [ l e a f i ] + d i s [ l c a ( x , l e a f i ) ] } \max_{i\leq 2y-1}\{-dis[leaf_i]+dis[lca(x,leaf_i)]\}

改成枚举 l c a lca 即可得到

max a n c r a n k [ f a r [ a n c ] ] 2 y 1 { d i s [ f a r [ a n c ] ] + d i s [ a n c ] } \max_{anc}^{rank[far[anc]]\leq 2y-1}\{-dis[far[anc]]+dis[anc]\}

仔细观察,发现祖先的 r a n k rank 是单调递减的,大括号里的式子也是单调递减的,那么直接倍增即可找到最优的祖先。

时间复杂度 O ( ( n + m ) log n ) O((n+m)\log n)

Code

#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=100010;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
struct data{int v,w,nxt;}edge[maxn<<1];
int n,m,p,rt,ans,head[maxn],dis[maxn],cp[maxn];
int cmp(const int &x,const int &y){return cp[x]>cp[y];}
struct Tree{
	int cnt,lf[maxn],sum[maxn],id[maxn],val[maxn],rk[maxn];
	int hs[maxn],far[maxn],dis[maxn],f[17][maxn];
	void dfs1(int x)
	{
		int fg=1;
		for(int i=1;i<17;i++) f[i][x]=f[i-1][f[i-1][x]];
		for(int i=head[x];i;i=edge[i].nxt)
		  if(edge[i].v^f[0][x])
		  {
		  	fg=0;f[0][edge[i].v]=x;dis[edge[i].v]=dis[x]+edge[i].w;
		  	dfs1(edge[i].v);
		  	if(dis[far[hs[x]]]<dis[far[edge[i].v]])
		  	  hs[x]=edge[i].v,far[x]=far[edge[i].v];
		  }
		if(fg){lf[++cnt]=x;far[x]=x;}
	}
	void dfs2(int x,int v)
	{
		val[x]=v;
		for(int i=head[x];i;i=edge[i].nxt)
		  if(edge[i].v^f[0][x])
		  {
		  	if(edge[i].v^hs[x]) dfs2(edge[i].v,edge[i].w);
		  	else dfs2(edge[i].v,v+edge[i].w);
		  }
	}
	void init(int rt)
	{
		dfs1(rt);
		dfs2(rt,0);
		memmove(cp,val,sizeof(val));
		sort(lf+1,lf+cnt+1,cmp);
		for(int i=1;i<=cnt;i++) rk[lf[i]]=i,sum[i]=sum[i-1]+val[lf[i]];
		for(int i=1;i<=n;i++) id[i]=rk[far[i]];
	}
	int query(int x,int y)
	{
		if(y>=cnt) return sum[cnt];
		if(y>=id[x]) return sum[y];
		int t=far[x];
		for(int i=16;~i;i--) if(f[i][x]&&id[f[i][x]]>y) x=f[i][x];
		x=f[0][x];
		return sum[y]+dis[t]-dis[x]-min(dis[far[x]]-dis[x],val[lf[y]]);
	}
}A,B;
void insert(int u,int v,int w)
{
	edge[++p]=(data){v,w,head[u]};head[u]=p;
	edge[++p]=(data){u,w,head[v]};head[v]=p;
}
void dfs(int x,int pre)
{
	if(dis[x]>dis[rt]) rt=x;
	for(int i=head[x];i;i=edge[i].nxt)
	  if(edge[i].v^pre)
	  {
	  	dis[edge[i].v]=dis[x]+edge[i].w;
	  	dfs(edge[i].v,x);
	  }
}
void input()
{
	int u,v,w;
	read(n);read(m);
	for(int i=1;i<n;i++)
	{
		read(u);read(v);read(w);
		insert(u,v,w);
	}
	dfs(1,1);
	A.init(rt);
	dis[rt]=0;dfs(rt,rt);
	B.init(rt);
}
int main()
{
	int x,y;
	input();
	while(m--)
	{
		read(x);read(y);
		x=(x+ans-1)%n+1;y=(y+ans-1)%n+1;
		y=(y<<1)-1;
		printf("%d\n",ans=max(A.query(x,y),B.query(x,y)));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/As_A_Kid/article/details/88825177
今日推荐