• [Luogu3345][ZJOI2015]幻想乡战略游戏


    Luogu
    题意:
    动态维护带权重心。

    sol

    这是一道写起来很舒服的动态点分治。(不像某些毒瘤题)
    我们考虑,如果你选择的补给点不是当前的带权重心,那么带权重心就在补给点的一个子树中(你把补给点当做根的话)。那么,你把补给点向带权重心所在的子树中移动的时候,答案一定会减小。换言之,如果补给点无论向哪个方向移动答案都不会减小,那么这个点就是带权重心。
    所以我们每次考虑移动补给点然后计算即可。
    但是怎么移动呢?
    最优复杂度的移动策略是:先假设点分树的根就是补给,然后你一次检查与它在原树中相连的所有点,如果有一个比它小(这样的点至多有一个),这时候你不是直接跳向这个点,而是跳向点分树中的那个儿子。这样在保证了解的范围的同时也保证了复杂度,因为点分树的树高是(log n),所以最多向下跳(log n)
    次。
    主题思想解决了,现在我们考虑怎么快速计算出以某一个点为补给点时的答案。
    我们记一下三个变量(不要吐槽变量名)
    (sum_i):表示点分树中以i为根的子树的权值和
    (gather_i):表示点分树中以i为根的子树全部集合到i的总耗费
    (tofa_i)表示点分树中以i为根的子树全部集合到i在点分树中的父节点的总耗费
    可以发现其实(gather_u=sum tofa_v),其中v是u在点分树中的儿子。之所以这样记是为了去除重复计算。
    具体怎么算请自行YY。(YY有益身心健康)
    总的算起来复杂度是(O(nlog^3n))(但显然不满的),如果你写(RMQLCA)的话就是(O(nlog^2n))

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 100005;
    #define ll long long
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    int n,m,dis[N],sum[N];
    ll gather[N],tofa[N];
    struct edge{int to,next,w;}a[N<<1];
    int head[N],cnt,pa[N],dep[N],sz[N],son[N],top[N];
    void dfs1(int u,int f)
    {
    	pa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
    	for (int e=head[u];e;e=a[e].next)
    	{
    		int v=a[e].to;if (v==f) continue;
    		dis[v]=dis[u]+a[e].w;dfs1(v,u);
    		sz[u]+=sz[v];if (sz[v]>sz[son[u]]) son[u]=v;
    	}
    }
    void dfs2(int u,int up)
    {
    	top[u]=up;
    	if (son[u]) dfs2(son[u],up);
    	for (int e=head[u];e;e=a[e].next)
    		if (a[e].to!=pa[u]&&a[e].to!=son[u])
    			dfs2(a[e].to,a[e].to);
    }
    int lca(int u,int v)
    {
    	while (top[u]^top[v])
    	{
    		if (dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=pa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    int getdis(int u,int v){return dis[u]+dis[v]-2*dis[lca(u,v)];}
    struct node{int to,next,rt;}G[N];
    int vis[N],w[N],fa[N],root,tot,RT,ft[N];
    void getroot(int u,int f)
    {
    	sz[u]=1;w[u]=0;
    	for (int e=head[u];e;e=a[e].next)
    	{
    		int v=a[e].to;if (v==f||vis[v]) continue;
    		getroot(v,u);
    		sz[u]+=sz[v];w[u]=max(w[u],sz[v]);
    	}
    	w[u]=max(w[u],tot-sz[u]);
    	if (w[u]<w[root]) root=u;
    }
    void solve(int u,int f)
    {
    	fa[u]=f;vis[u]=1;int pre_tot=tot;
    	for (int e=head[u];e;e=a[e].next)
    	{
    		int v=a[e].to;if (vis[v]) continue;
    		if (sz[v]>sz[u]) tot=pre_tot-sz[u];
    		else tot=sz[v];
    		root=0;
    		getroot(v,0);
    		G[++cnt]=(node){v,ft[u],root};ft[u]=cnt;
    		solve(root,u);
    	}
    }
    void Modify(int u,int val)
    {
    	sum[u]+=val;
    	for (int i=u;fa[i];i=fa[i])
    	{
    		int dist=getdis(u,fa[i]);
    		sum[fa[i]]+=val;
    		gather[fa[i]]+=(ll)val*dist;
    		tofa[i]+=(ll)val*dist;
    	}
    }
    ll calc(int u)
    {
    	ll res=gather[u];
    	for (int i=u;fa[i];i=fa[i])
    	{
    		int dist=getdis(u,fa[i]);
    		res+=(ll)(sum[fa[i]]-sum[i])*dist;
    		res+=gather[fa[i]]-tofa[i];
    	}
    	return res;
    }
    ll Query(int u)
    {
    	ll temp=calc(u);
    	for (int e=ft[u];e;e=G[e].next)
    		if (calc(G[e].to)<temp) return Query(G[e].rt);
    	return temp;
    }
    int main()
    {
    	n=gi();m=gi();
    	for (int i=1;i<n;i++)
    	{
    		int u=gi(),v=gi(),w=gi();
    		a[++cnt]=(edge){v,head[u],w};head[u]=cnt;
    		a[++cnt]=(edge){u,head[v],w};head[v]=cnt;
    	}
    	dfs1(1,0);dfs2(1,1);
    	w[0]=tot=n;cnt=0;
    	getroot(1,0);
    	RT=root;
    	solve(root,0);
    	while (m--)
    	{
    		int u=gi(),e=gi();
    		Modify(u,e);
    		printf("%lld
    ",Query(RT));
    	}
    	return 0;
    }
    
  • 相关阅读:
    HDU1412:{A} + {B}
    [置顶] 写好最简单的冒泡排序
    python scrapy 基础
    hdu2531之BFS
    Direct3D 11的流水线
    Direct3D 11的资源
    Perl 多线程模块 Parallel::ForkManager
    POJ 3450 Corporate Identity (KMP+暴搞)
    hdu 2853
    我所理解的设计模式(C++实现)——中介者模式(Mediator Pattern)
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8277944.html
Copyright © 2020-2023  润新知