• 6837. 【2020.10.31提高组模拟】小y的数论


    一棵树,带边权。若干次询问:询问编号([l,r])内的点中,选出(k)个点,建出的虚树的边权和最大是多少。

    (n,mle 3*10^5)


    结论题+码农题。

    原题题解中解释,但是题解中冒出若干个题目没有出现过的字母,以及很长的形式化的式子,也不加解释,感觉就是出题人在自嗨。总之就是看不懂。

    首先,如何求([1,n])的答案。有个结论是:(k)的最优解一定包含(k-1)的最优解。那么每次找到没有选过的最长链。可以发现这其实可以以直径端点为根长链剖分,选前(k-1)长的链。

    另一个结论:设(p_{S,k})表示(k)为多少时,(S)的最优解。那么一定有(p_{Sigcup T,k}subseteq p_{S,k}igcup p_{T,k})

    于是求(p_{Sigcup T,k})时,可以以(p_{S,k}igcup p_{T,k})中的点建虚树,然后套用上面的方法来求出最优解。

    因此(p_{S,k})是可以维护的。以(K)(k)的最大值)分块,对于(frac{n}{K})个块建ST表即可,查询的时候用ST表查整块暴力查散块,合并起来求最优解即可。

    时间复杂度(O(nlg n+qKlg K))。后面(lg k)其实可以省掉但是没有必要因为省掉之后代码量增大并且常数也大。


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    #include <vector>
    #include <cassert>
    #include <cstdlib>
    #define N 300005
    #define maxK 100
    #define ll long long
    int n;
    struct EDGE{
    	int to;
    	ll w;
    	EDGE *las;
    };
    struct Graph{
    	EDGE e[N*2];
    	int ne;
    	EDGE *last[N];
    	void link(int u,int v,ll w){
    //		printf("%d %d %lld
    ",u,v,w);
    		e[ne]={v,w,last[u]};
    		last[u]=e+ne++;
    	}
    } G,F;
    int fa[N],dep[N],siz[N],hs[N],top[N],dfn[N],nowdfn;
    ll sum[N];
    void init1(int x){
    	siz[x]=1;
    	for (EDGE *ei=G.last[x];ei;ei=ei->las)
    		if (ei->to!=fa[x]){
    			fa[ei->to]=x;
    			dep[ei->to]=dep[x]+1;
    			sum[ei->to]=sum[x]+ei->w;
    			init1(ei->to);
    			siz[x]+=siz[ei->to];
    			if (siz[ei->to]>siz[hs[x]])
    				hs[x]=ei->to;
    		}
    }
    void init2(int x,int t){
    	top[x]=t;
    	dfn[x]=++nowdfn;
    	if (hs[x]){
    		init2(hs[x],t);
    		for (EDGE *ei=G.last[x];ei;ei=ei->las)
    			if (ei->to!=fa[x] && ei->to!=hs[x])
    				init2(ei->to,ei->to);
    	}
    }
    int LCA(int u,int v){
    	for (;top[u]!=top[v];u=fa[top[u]])
    		if (dep[top[u]]<dep[top[v]])
    			swap(u,v);
    	return dep[u]<dep[v]?u:v;
    }
    
    int K,bel[N],L[N],R[N],nb;
    vector<int> f[N/maxK+5][19];
    bool cmpdfn(int x,int y){return dfn[x]<dfn[y];}
    int g[N];
    int build(vector<int> &q,vector<int> &p){
    //	printf("-----
    ");
    //	printf("
    ");
    //	for (int i=1;i<q.size();++i)
    //		if (dfn[q[i-1]]>=dfn[q[i]])
    //			printf("fuck
    ");
    	assert(q.size()>=1);
    	static int st[N],tp;
    	p.clear();
    	st[tp=1]=q[0];	
    	for (int i=1;i<q.size();++i){
    		int lca=LCA(st[tp],q[i]);
    		while (tp>1 && dep[lca]<dep[st[tp-1]]){
    			F.link(st[tp-1],st[tp],sum[st[tp]]-sum[st[tp-1]]);
    			F.link(st[tp],st[tp-1],sum[st[tp]]-sum[st[tp-1]]);
    			g[st[tp]]=st[tp-1];
    			p.push_back(st[tp--]);
    		}
    		if (tp && dep[lca]<dep[st[tp]]){
    			F.link(lca,st[tp],sum[st[tp]]-sum[lca]);
    			F.link(st[tp],lca,sum[st[tp]]-sum[lca]);
    			g[st[tp]]=lca;
    			p.push_back(st[tp--]);
    			if (st[tp]!=lca)
    				st[++tp]=lca;
    		}
    		st[++tp]=q[i];
    	}
    	while (tp>1){
    		F.link(st[tp-1],st[tp],sum[st[tp]]-sum[st[tp-1]]);
    		F.link(st[tp],st[tp-1],sum[st[tp]]-sum[st[tp-1]]);
    		g[st[tp]]=st[tp-1];
    		p.push_back(st[tp--]);
    	}
    	p.push_back(st[1]);
    //	printf("------
    ");
    	return st[1];
    }
    ll dis[N];
    void getdis(int x,int fa){
    //	if (fa!=g[x])
    //		printf("%d
    ",x);
    	for (EDGE *ei=F.last[x];ei;ei=ei->las)
    		if (ei->to!=fa){
    			if (dis[ei->to]==0){
    //				printf("%d
    ",ei->to);
    				assert(dis[ei->to]==0);
    			}
    			dis[ei->to]=dis[x]+ei->w;
    			getdis(ei->to,x);
    		}
    }
    ll len[N];
    int bot[N];
    vector<int> t;
    bool cmpt(int x,int y){return len[x]>len[y];}
    void work(int x,int fa){
    	len[x]=0;
    	bot[x]=x;
    	for (EDGE *ei=F.last[x];ei;ei=ei->las)
    		if (ei->to!=fa){
    			work(ei->to,x);
    			len[ei->to]+=ei->w;
    			if (len[ei->to]>len[x])
    				len[x]=len[ei->to],bot[x]=bot[ei->to];
    		}
    	for (EDGE *ei=F.last[x];ei;ei=ei->las)
    		if (ei->to!=fa && bot[ei->to]!=bot[x])
    			t.push_back(ei->to);
    }
    void merge(vector<int> &c,vector<int> &a,vector<int> &b){
    	static vector<int> q;
    	q.clear();
    	int i=0,j=0;
    	while (i<a.size() && j<b.size())
    		if (dfn[a[i]]<dfn[b[j]])
    			q.push_back(a[i++]);
    		else if (dfn[a[i]]>dfn[b[j]])
    			q.push_back(b[j++]);
    		else
    			q.push_back(a[i++]),j++;
    	for (;i<a.size();++i)
    		q.push_back(a[i]);
    	for (;j<b.size();++j)
    		q.push_back(b[j]);
    	c=q;
    }
    ll calc(vector<int> &q,int k=K){
    	static vector<int> p;
    	int rt=build(q,p);
    	dis[rt]=0,getdis(rt,0);
    //	exit(0);
    	for (int i=0;i<p.size();++i)
    		if (dis[p[i]]>dis[rt])
    			rt=p[i];
    	t.clear(),work(rt,0),t.push_back(rt);
    	q.clear(),q.push_back(rt);
    	ll res=0;
    	if (p.size()>1){
    		if (t.size()>k-1)
    			sort(t.begin(),t.end(),cmpt);
    		for (int i=0;i<t.size() && i<k-1;++i){
    			q.push_back(bot[t[i]]);
    			res+=len[t[i]];
    		}
    	}
    	sort(q.begin(),q.end(),cmpdfn);
    	F.ne=0;
    	for (int i=0;i<p.size();++i)
    		F.last[p[i]]=NULL;
    	return res;
    }
    int lg[N];
    ll query(int l,int r,int k){
    	static vector<int> q,p;
    	if (bel[l]==bel[r]){
    		p.clear();
    		for (int i=l;i<=r;++i)
    			p.push_back(i);
    		sort(p.begin(),p.end(),cmpdfn);
    		return calc(p,k);
    	}
    	int Lb=bel[l]+1,Rb=bel[r]-1;
    	if (Lb<=Rb){
    		int m=lg[Rb-Lb+1];
    		merge(q,f[Lb][m],f[Rb-(1<<m)+1][m]);
    	}
    	else
    		q.clear();
    	p.clear();
    	for (int i=l;i<=R[bel[l]];++i)
    		p.push_back(i);
    	for (int i=r;i>=L[bel[r]];--i)
    		p.push_back(i);
    	sort(p.begin(),p.end(),cmpdfn);
    	merge(q,q,p);
    	return calc(q,k);
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	freopen("number.in","r",stdin);
    	freopen("number.out","w",stdout);	 	 
    	scanf("%d",&n);
    	lg[0]=-1,lg[1]=0;
    	for (int i=2;i<=n;++i)
    		lg[i]=lg[i>>1]+1;
    	for (int i=1;i<n;++i){
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		G.link(u,v,w),G.link(v,u,w);
    	}
    	init1(1),init2(1,1);
    	K=min(n,maxK);
    	for (int i=1;i<=n;++i)
    		bel[i]=(i-1)/K+1,R[bel[i]]=i,nb=bel[i];
    	for (int i=n;i>=1;--i)
    		L[bel[i]]=i;
    	for (int i=1;i<=nb;++i){
    		for (int j=L[i];j<=R[i];++j)
    			f[i][0].push_back(j);
    		sort(f[i][0].begin(),f[i][0].end(),cmpdfn);
    	}
    	for (int j=1;1<<j<=nb;++j){
    		for (int i=1;i+(1<<j)-1<=nb;++i){
    			merge(f[i][j],f[i][j-1],f[i+(1<<j-1)][j-1]);
    			calc(f[i][j]);	
    //			sort(f[i][j].begin(),f[i][j].end(),cmpdfn);
    		}
    	}
    	int Q;
    	scanf("%d",&Q);
    	int cnt=0;
    	while (Q--){
    		int l,r,k;
    		scanf("%d%d%d",&l,&r,&k);
    		printf("%lld
    ",query(l,r,k));
    	}
    	return 0;
    }
    
  • 相关阅读:
    10月9日学习日志
    10月2日学习日志
    11月3日学习日志
    10月5日学习日志
    10月6日学习日志
    10月7日学习日志
    11月4日学习日志
    AccessDatabaseEngine.exe 32位64安装失败问题
    国产各安卓系统接收消息在杀进程后
    SAP容差组
  • 原文地址:https://www.cnblogs.com/jz-597/p/13912667.html
Copyright © 2020-2023  润新知