• 虚树


    一般用到只跟点数有关,多次查询的题目时就会用到虚树,同时还要支持快速查询点之间的信息

    下面是消耗战的例子

    神仙的博客

    注意,这道题目的例子有点特殊,所以那位神仙的代码并不是一般题目通用的,但是我的代码是通用的

    注意,1一定要加入点集中

    #include<bits/stdc++.h>
    #define vit vector<int>::iterator 
    typedef long long ll;
    using namespace std;
    const int N=2.9e5;
    const int Log=20;
    const ll inf=1e15+7;
    struct edge
    {
    	int to,nxt,co;
    }e[N*2];
    int h[N],E=0;
    int siz[N],son[N],dfn[N],mp[N],pa[N],dep[N],top[N],tim=0;
    ll st[Log+5][N],p2[Log+5],l2[N],tof[N];
    int a[N];
    int n,m,k;
    int s[N],Top=0;
    int used[N];
    ll f[N];
    vector<int> g[N];
    void addedge(int u,int v,int w)
    {
    	E++;
    	e[E].to=v,e[E].nxt=h[u],e[E].co=w;
    	h[u]=E;
    	return;
    }
    void vaddedg(int u,int v)
    {
    	g[u].push_back(v);
    	return;
    }
    void dfs1(int u,int fa,ll co)
    {
    	tof[u]=co;
    	dep[u]=dep[fa]+1;
    	siz[u]=1;
    	pa[u]=fa;
    	son[u]=-1;
    	for(int i=h[u];i;i=e[i].nxt)
    	{
    		int v=e[i].to;
    		int w=e[i].co;
    		if(v==fa) continue;
    		dfs1(v,u,w);
    		siz[u]+=siz[v];
    		if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;
    	}
    	return;
    }
    void dfs2(int u,int fa)
    {
    	if(!top[u]) top[u]=u;
    	tim++;
    	dfn[u]=tim;
    	mp[tim]=u;
    	st[0][tim]=tof[u];
    	if(son[u]!=-1) top[son[u]]=top[u],dfs2(son[u],u);
    	for(int i=h[u];i;i=e[i].nxt)
    	{
    		int v=e[i].to;
    		if(v==fa||v==son[u]) continue;
    		dfs2(v,u);
    	}
    	return;
    }
    int LCA(int u,int v)
    {
    	for(;top[u]!=top[v];)
    	{
    		if(dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=pa[top[u]];
    	}
    	if(dep[u]>dep[v]) swap(u,v);
    	return u;
    }
    ll que(int l,int r)
    {
    	if(l>r) return inf;
    	int s=l2[r-l+1];
    	return min(st[s][l],st[s][r-p2[s]+1]);
    }
    ll cal(int u,int to)
    {
    	ll res=inf;
    	for(;dep[top[u]]>dep[to];u=pa[top[u]]) res=min(res,que(dfn[top[u]],dfn[u]));
    	res=min(res,que(dfn[to]+1,dfn[u]));
    	return res;
    }
    void Init()
    {
    	p2[0]=1;
    	for(int i=1;i<=Log;i++) p2[i]=p2[i-1]*2;
    	l2[0]=-1;
    	for(int i=1;i<=n;i++) l2[i]=l2[i/2]+1;
    	for(int i=1;i<=Log;i++)
    		for(int j=1;j+p2[i]-1<=n;j++)
    			st[i][j]=min(st[i-1][j],st[i-1][j+p2[i-1]]);
    	return;
    }
    int cmp(int a,int b)
    {
    	return dfn[a]<dfn[b];
    }
    void vins(int x)
    {
    	if(!Top) return void(s[++Top]=x);
    	int lca=LCA(x,s[Top]);
    	if(lca==s[Top]) return void(s[++Top]=x);
    	while(Top>1&&dfn[s[Top-1]]>=dfn[lca]) vaddedg(s[Top-1],s[Top]),Top--;
    	if(lca!=s[Top]) vaddedg(lca,s[Top]),s[Top]=lca;
    	s[++Top]=x;
    	return;
    }
    void DP(int u,ll co)
    {
    	f[u]=0;
    	for(vit it=g[u].begin();it!=g[u].end();it++)
    	{
    		int v=*it;
    		int w=cal(v,u);
    		DP(v,w);
    		f[u]+=f[v];
    	}
    	if(used[u]) f[u]=co;
    	else f[u]=min(f[u],co);
    	g[u].clear();
    	return;
    }
    void build(int k)
    {
    	for(int i=1;i<=k;i++) scanf("%d",&a[i]);
    	sort(a+1,a+k+1,cmp);
    	s[Top=1]=1;
    	for(int i=1;i<=k;i++)
    	{
    		vins(a[i]);
    		used[a[i]]=1;
    	}	
    	while(Top>1) vaddedg(s[Top-1],s[Top]),Top--;
    	DP(1,inf); 
    	for(int i=1;i<=k;i++) used[a[i]]=0;
    	return;
    }
    int main()
    {
    	scanf("%d",&n);
    	int u,v,w;
    	for(int i=1;i<=n-1;i++)
    	{
    		scanf("%d%d%d",&u,&v,&w);
    		addedge(u,v,w);
    		addedge(v,u,w);
    	}
    	dep[0]=-1;
    	dfs1(1,0,inf);
    	dfs2(1,0);
    	Init();
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d",&k);
    		build(k);
    		printf("%lld\n",f[1]);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    [Winform]Media Player com组件应用中遇到的问题
    [Winform]Media Player播放控制面板控制,单击事件截获
    [Winform]Media Player组件全屏播放的设置
    [EF]数据上下文该如何实例化?
    [Winform]在关闭程序后,托盘不会消失的问题
    咏南中间件跨平台解决方案
    硬件中间件
    BASE64使用场景
    DELPHI7 ADO二层升三层新增LINUX服务器方案
    NGINX心跳检测
  • 原文地址:https://www.cnblogs.com/SegmentTree/p/12981755.html
Copyright © 2020-2023  润新知