• ZJOI 2015 幻想乡战略游戏(动态点分治)


    题意

    https://loj.ac/problem/2135

    思路

    首先要明确一点,答案分布是有单调性的。什么意思呢?假设我们的答案在 (u) 节点,((u,v)) 之间有一条边且 (u) 离答案所在的点更近,那么 (u) 节点作为答案一定不比在 (v) 节点作答案劣。从链的角度分析在拓展到树上会比较好理解这个性质。

    那么如果树是一棵完全二叉树,就可以 (log n) 的回答了。从根节点向下跳,每次如果找到一个 (displaystyle2*sum[u]geq tot)(sum[u])(u) 子树点权之和, (tot) 为整张图点权之和)的节点,就说明存在一个更优或不劣的答案,就往这个方向跳,直到不能跳为止。更新时直接暴力修改父亲,没什么可说的。

    虽然这棵树不一定是完全二叉树,但是这棵树的“分治树”高度一定是不超过 (log n) 的(我个人不习惯使用“分治树”的概念,而将点分治理解为重心管辖区域这样的概念)。那么就对这棵树进行点分,存下每个数对应的每一层重心对应容器的标号,到它的距离,以及是容是斥。此题的每层重心的容器就是两个变量 (Sum,sum) ,其中 (Sum) 表示此重心管辖区域权值乘距离总和,(sum) 表示权值总和。那么对于 (u) 一层重心对应容器编号为 (id) ,距离 (dis) ,容斥系数为 (s) ,产生贡献即为 (s(Sum[id]+discdot sum[id])) 。那么就能 (O(log n)) 的询问取某个点的答案是多少了。

    修改仍为暴力修改,没什么好说的。

    关键在于回答询问,我们从整张图的重心 (u​) 开始跳,这个重心 (u​) 将树劈成了若干个连通块(题目有条件,最多 (20​) 个),对于其中一个连通块,我们设 (v​) 在这个连通块内且与 (u​) 有边。我们查询选 (v​) 的得到的答案,如果小于等于 (u​) 的答案,那么就要跳了。妙的是这里跳的是这个连通块的重心 (w​),这样就可以保证复杂度了。所以,在点分的时候就要顺便把每个层重心 (u​) 的下层重心 (w​) ,以及对应的 (v​) 存下来。复杂度 (O(20 cdot nlog ^2n)​) ,还是挺飘的。

    代码

    #include<bits/stdc++.h>
    #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
    #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
    using namespace std;
    template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
    template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
    typedef long long ll;
    const int N=1e5+5;
    template<const int maxn,const int maxm>struct Linked_list
    {
    	int head[maxn],to[maxm],nxt[maxm],cost[maxm],tot;
    	Linked_list(){clear();}
    	void clear(){memset(head,-1,sizeof(head));tot=0;}
    	void add(int u,int v,int w){to[++tot]=v,cost[tot]=w,nxt[tot]=head[u],head[u]=tot;}
    	#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
    };
    Linked_list<N,N<<1>G,H;
    ll sum[N*2],Sum[N*2];int Sc;
    int lv[N],Sid[N][40];ll dis[N][40];bool sgn[N][40];
    int sz[N];bool mark[N];
    int n,q;
    
    void CFS(int u,int f,int tot,int &C,int &Mi)
    {
    	sz[u]=1;int res=0;
    	EOR(i,G,u)
    	{
    		int v=G.to[i];
    		if(v==f||mark[v])continue;
    		CFS(v,u,tot,C,Mi);
    		sz[u]+=sz[v];
    		res=max(res,sz[v]);
    	}
    	res=max(res,tot-sz[u]);
    	if(chk_min(Mi,res))C=u;
    }
    void dfs_init(int u,int f,ll D,bool s)
    {
    	Sid[u][++lv[u]]=Sc,dis[u][lv[u]]=D,sgn[u][lv[u]]=s;
    	EOR(i,G,u)
    	{
    		int v=G.to[i],w=G.cost[i];
    		if(v==f||mark[v])continue;
    		dfs_init(v,u,D+w,s);
    	}
    }
    void dac(int u,int f,int tot)
    {
    	int rt=u,Mi=1e9;
    	CFS(u,0,tot,u,Mi);
    	if(f)H.add(f,u,rt);
    	mark[u]=1;
    	Sc++,dfs_init(u,0,0,1);
    	
    	EOR(i,G,u)
    	{
    		int v=G.to[i],w=G.cost[i];
    		if(mark[v])continue;
    		Sc++,dfs_init(v,u,w,0);
    		dac(v,u,sz[u]>sz[v]?sz[v]:tot-sz[u]);
    	}
    }
    void update(int u,int val)
    {
    	FOR(i,1,lv[u])
    	{
    		int id=Sid[u][i];ll d=dis[u][i];
    		sum[id]+=val;
    		Sum[id]+=(ll)val*d;
    	}
    }
    ll query(int u)
    {
    	ll res=0;
    	FOR(i,1,lv[u])
    	{
    		int id=Sid[u][i];ll d=dis[u][i];bool s=sgn[u][i];
    		if(s)res+=Sum[id]+d*sum[id];
    		else res-=Sum[id]+d*sum[id];
    	}
    	return res;
    }
    ll Query(int u)
    {
    	ll res=query(u);
    	EOR(i,H,u)
    	{
    		int v=H.to[i],w=H.cost[i];
    		if(query(w)<=res)return Query(v);
    	}
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d",&n,&q);
    	FOR(i,1,n-1)
    	{
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		G.add(u,v,w),G.add(v,u,w);
    	}
    	int C,Mi=1e9;
    	CFS(1,0,n,C,Mi);
    	memset(mark,0,sizeof(mark));
    	memset(lv,0,sizeof(lv));
    	Sc=0;
    	dac(1,0,n);
    	while(q--)
    	{
    		int u,val;
    		scanf("%d%d",&u,&val);
    		update(u,val);
    		printf("%lld
    ",Query(C));
    	}
    	return 0;
    }
    
  • 相关阅读:
    C#怎样保证弹出窗体是唯一并居中显示
    1、怎样设置C#OpenFileDialog(文件选择窗体)的指定路径、文件格式等属性(设置打开默认路径、文件格式、窗体显示文本)
    FTP在CentOS上安装与使用
    nano在CentOS上的安装和使用
    CentOS 7 安装php5.6,Nginx,Memcached环境及配置
    PhpStorm 2017.1安装及破解过程
    在唯一密钥属性“name”设置为“ExtensionlessUrlHandler-Integrated-4.0”时,无法添加类型为“add”的重复集合项
    获取含有字符串数组里元素的数据,并批量删除
    如何去掉browserLinkSignalR
    使用VS2015开发asp程序让IIS express 允许的父路径的方法
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10249553.html
Copyright © 2020-2023  润新知