CF526G Spiders Evil Plan

\(\color{#FF003F}{\texttt {CF526G Spiders Evil Plan}}\)

先考虑单次询问。发现 \(y\) 条路径的端点一定是叶子节点,产生的联通块最多会有 \(2y\) 个叶子。但还是不好做。

考虑一个相似的问题:一棵有根树,选 \(k\) 个点,最大化这 \(k\) 个点到根节点路径的并的大小。

选的点肯定是叶子。如果 \(k \geq\) 叶子个数,答案肯定是 \(n\)

否则定义一个点的贡献为 \(V_i\)\(i\) 到根节点上没被经过的点的个数。每次选 \(V_i\) 最大的肯定最优。

性质:每个点一定在其长链顶端的父亲所在长链底端的点被选后被选。

那么 \(V_i=dep_i-dep_{fa_{top_i}}\),直接贪心。

如果有多次询问,考虑优化上述做法的复杂度。
有一个性质,直径的一个端点端点一定会被选中。
不妨以直径端点为根,那么还要选 \(2y-1\) 个叶子。预处理下即可。

考虑原问题。若直接用上述做法,可能 \(x\) 不在联通块内。

有两种策略进行调整

  1. 删除第 \(2y-1\) 个点,加入 \(x\) 的子树内 \(V_i\) 最大的点。

  2. 找到 \(x\) 的祖先中离 \(x\) 最近的被覆盖的点,删除它子树中被选的一个叶子,加入 \(x\) 的子树内 \(V_i\) 最大的点。

发现 \(2\) 策略不是很好维护。但是如果 \(2\) 策略比 \(1\) 策略优,那么 \(x\) 的祖先中离 \(x\) 最近的被覆盖的点的子树中只能有 \(1\) 个被选中的点。
倍增往上跳即可。

复杂度 \(O((n+q)\log n)\)

// Author -- Frame

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<iostream>

#define lowbit(x) ((x)&(-x))
#define Finline __inline__ __attribute__ ((always_inline))
#define DEBUG fprintf(stderr,"Running on Line %d in Function %s\n",__LINE__,__FUNCTION__)

typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;

const int inf=0x3f3f3f3f,Inf=0x7fffffff;
const ll INF=0x7fffffffffffffff;
const double eps=1e-10;

template <typename _Tp>_Tp gcd(const _Tp &a,const _Tp &b){return (!b)?a:gcd(b,a%b);}
template <typename _Tp>Finline _Tp abs(const _Tp &a){return a>=0?a:-a;}
template <typename _Tp>Finline _Tp max(const _Tp &a,const _Tp &b){return a<b?b:a;}
template <typename _Tp>Finline _Tp min(const _Tp &a,const _Tp &b){return a<b?a:b;}
template <typename _Tp>Finline void chmax(_Tp &a,const _Tp &b){(a<b)&&(a=b);}
template <typename _Tp>Finline void chmin(_Tp &a,const _Tp &b){(b<a)&&(a=b);}
template <typename _Tp>Finline bool _cmp(const _Tp &a,const _Tp &b){return abs(a-b)<=eps;}
template <typename _Tp>Finline void read(_Tp &x)
{
	register char ch(getchar());
	bool f(false);
	while(ch<48||ch>57) f|=ch==45,ch=getchar();
	x=ch&15,ch=getchar();
	while(ch>=48&&ch<=57) x=(((x<<2)+x)<<1)+(ch&15),ch=getchar();
	if(f) x=-x;
}
template <typename _Tp,typename... Args>Finline void read(_Tp &t,Args &...args)
{
	read(t);read(args...);
}
Finline int read_str(char *s)
{
	register char ch(getchar());
	while(ch==' '||ch=='\r'||ch=='\n') ch=getchar();
	register char *tar=s;
	*tar=ch,ch=getchar();
	while(ch!=' '&&ch!='\r'&&ch!='\n'&&ch!=EOF) *(++tar)=ch,ch=getchar();
	return tar-s+1;
}

const int N=100005;
struct edge{
	int v,nxt,w;
}c[N<<1];
int front[N],cnt_;
Finline void add(int u,int v,int w)
{
	c[++cnt_]=(edge){v,front[u],w},front[u]=cnt_;
}
struct node{
	int val,id;
	Finline bool operator < (const node &o)const
	{
		return val>o.val;
	}
};
struct Tree{
	int root;
	int len[N],son[N],Fa[N],top[N];
	int dis[N];
	int f[N][19],w[N][19];
	void dfs1(int x,int fa)
	{
		Fa[x]=fa;
		for(int i=front[x];i;i=c[i].nxt)
		{
			if(c[i].v!=fa)
			{
				dis[c[i].v]=dis[x]+c[i].w;
				dfs1(c[i].v,x);
				if(len[c[i].v]+c[i].w>len[x])
				{
					len[x]=len[c[i].v]+c[i].w;
					son[x]=c[i].v;
				}
			}
		}
	}
	node a[N];
	int pos;
	void dfs2(int x,int topf)
	{
		top[x]=topf;
		if(!son[x])
		{
			a[++pos]=(node){dis[x]-dis[Fa[topf]],x};
			return;
		}
		dfs2(son[x],topf);
		for(int i=front[x];i;i=c[i].nxt)
		{
			if(!top[c[i].v])
			{
				dfs2(c[i].v,c[i].v);
			}
		}
	}
	int tim[N];
	void dfs3(int x,int fa)
	{
		f[x][0]=fa;
		for(int i=1;i<=18;++i)
		{
			f[x][i]=f[f[x][i-1]][i-1];
		}
		for(int i=front[x];i;i=c[i].nxt)
		{
			if(c[i].v!=fa)
			{
				dfs3(c[i].v,x);
				chmin(tim[x],tim[c[i].v]);
			}
		}
	}
	int ans[N];
	void init(int _root)
	{
		memset(tim,63,sizeof(tim));
		root=_root;
		dfs1(root,0);
		dfs2(root,root);
		std::sort(a+1,a+pos+1);
		for(int i=1;i<=pos;++i)
		{
			tim[a[i].id]=i;
			ans[i]=ans[i-1]+a[i].val;
		}
		dfs3(root,0);
	}
	int getans(int x,int k)
	{
		if(tim[x]<=k)
		{
			return ans[k];
		}
		int cur=x;
		for(int i=18;i>=0;--i)
		{
			if(f[cur][i]&&tim[f[cur][i]]>k)
			{
				cur=f[cur][i];
			}
		}
		cur=Fa[cur];
		int res=ans[k]+len[x]+dis[x]-dis[cur]-len[cur];
		cur=x;
		for(int i=18;i>=0;--i)
		{
			if(f[cur][i]&&tim[f[cur][i]]>=k)
			{
				cur=f[cur][i];
			}
		}
		cur=Fa[cur];
		return max(res,ans[k-1]+len[x]+dis[x]-dis[cur]);
	}
}tr1,tr2;
int maxx=0,p;
void dfs(int x,int fa,int len)
{
	if(len>maxx)
	{
		maxx=len,p=x;
	}
	for(int i=front[x];i;i=c[i].nxt)
	{
		if(c[i].v!=fa)
		{
			dfs(c[i].v,x,len+c[i].w);
		}
	}
}
int dg[N];
int main()
{
	int n,q;
	read(n,q);
	int x,y,z;
	int sum=0;
	for(int i=1;i<n;++i)
	{
		read(x,y,z);
		add(x,y,z),add(y,x,z);
		sum+=z;
		++dg[x],++dg[y];
	}
	dfs(1,0,0);
	int root1=p;
	maxx=p=0;
	dfs(root1,0,0);
	int root2=p;
	tr1.init(root1);
	tr2.init(root2);
//	fprintf(stderr,"@ %d %d\n",root1,root2);
	int lastans=0;
	int cnt=0;
	for(int i=1;i<=n;++i)
	{
		cnt+=dg[i]==1;
	}
	while(q--)
	{
		read(x,y);
		x=(x+lastans-1)%n+1;
		y=(y+lastans-1)%n+1;
		if(y*2>=cnt)
		{
			printf("%d\n",lastans=sum);
			continue;
		}
		y=y*2-1;
		printf("%d\n",lastans=max(tr1.getans(x,y),tr2.getans(x,y)));
	}
	return 0;
}
posted @ 2020-03-28 16:01  xyr2005  阅读(163)  评论(0编辑  收藏  举报