zoukankan      html  css  js  c++  java
  • 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;
    }
    

    转载请注明出处

    https://www.cnblogs.com/xyr2005/

  • 相关阅读:
    P3383 【模板】线性筛素数
    POJ2431-Expedition【优先队列+贪心】
    HDU1087
    HDU1029
    最小生成树之Kruskal算法
    AC自动机模板
    328闯关解析
    php可获取客户端信息
    $( ).focus()与$( )[0].focus()区别
    RegExp类型和text()方法
  • 原文地址:https://www.cnblogs.com/xyr2005/p/12587814.html
Copyright © 2011-2022 走看看