zoukankan      html  css  js  c++  java
  • luogu P3345 [ZJOI2015]幻想乡战略游戏

    算是一道动态点分治入门题(我太弱了加起来学了三天)。

    拿到题首先考虑如何暴力,我们可以随机钦定一个点(不妨就设(1))为根节点,然后算出补给站设在该点的总花费,然后算出补给站在每个儿子时的总花费,显然最多只会有一个儿子花费比它(当前点)本身小(当且仅当(sum[u]<sum[son] imes 2)(sum[i])表示(i)号点子树内拥有的军队总数),如果存在这个花费比它小的儿子,就跳到它儿子上重复上述过程,如果不存在这个儿子,那么这个点就是答案。

    显然这样写一条链就没了,所以考虑用点分树来优化这个过程(下面其实就是动态点分治的套路了,跟本题关系不太大)。

    记三个值(sum[i],dis1[i],dis2[i])分别表示当前子树内的军队总数、当前子树内的点到当前子树根节点的总花费、当前子树内的点到当前子树根节点的父亲节点的总花费(注意这里所有子树的概念都是在点分树中)。

    这三个值在修改是可以暴力跳点分树维护,查询的时候也是暴力跳点分树就好了。时间复杂度(O(nlog^2n))

    (tips:)今天学会了如何(O(nlogn))预处理(ST)表然后(O(1))(LCA),其实就是类似一个欧拉序的东西,按照(dep)建立(ST)表,然后就能(O(1))得到(LCA)了。

    代码:

    #pragma GCC optimize(2)
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define rint int
    
    using namespace std;
    
    typedef long long LL;
    const int N=1000009;
    int n,Q,root,head[N],cnt,F[N],log[N];
    LL dis1[N],dis2[N],sum[N];
    struct Edge
    {
    	int nxt,to,w;
    }g[N*2];
    struct G
    {
    	int head[N],cnt,f[N][30],dep[N],del[N],siz[N],Euler[N],Fst[N],Index;
    	LL dis[N];
    	struct Edge
    	{
    		int nxt,to,w;
    	}g[N*2];
    	
    	void add(int from,int to,int w)
    	{
    		g[++cnt].nxt=head[from];
    		g[cnt].to=to;
    		g[cnt].w=w;
    		head[from]=cnt;
    	}
    	int LCA(int x,int y)
    	{
    		if(Fst[x]>Fst[y])
    			swap(x,y);
    		x=Fst[x],y=Fst[y];
    		int k=log[y-x+1];
    		return dep[f[x][k]]<dep[f[y-(1<<k)+1][k]]?f[x][k]:f[y-(1<<k)+1][k];
    	}
    	void dfs(int x,int fa)
    	{
    		Euler[++Index]=x,Fst[x]=Index,f[Index][0]=x;
    		for (rint i=head[x];i;i=g[i].nxt)
    		{
    			int v=g[i].to;
    			if(v==fa)
    				continue;
    			dep[v]=dep[x]+1,dis[v]=dis[x]+g[i].w;
    			dfs(v,x);
    			Euler[++Index]=x,f[Index][0]=x;
    		}
    	}
    	int Get_dis(int x,int y)
    	{
    		return dis[x]+dis[y]-2*dis[LCA(x,y)];
    	}
    	void DFS(int x,int fa)
    	{
    		siz[x]=1;
    		for (rint i=head[x];i;i=g[i].nxt)
    		{
    			int v=g[i].to;
    			if(v==fa||del[v])
    				continue;
    			DFS(v,x);
    			siz[x]+=siz[v];
    		}
    	}
    	int Get_Weight(int x)
    	{
    		DFS(x,-1);
    		int k=siz[x]/2,fa=-1;
    		while(1)
    		{
    			int tmp=0;
    			for (rint i=head[x];i;i=g[i].nxt)
    			{
    				int v=g[i].to;
    				if(v==fa||del[v])
    					continue;
    				if(siz[v]>siz[tmp])
    					tmp=v;
    			}
    			if(siz[tmp]<=k)
    				return x;
    			fa=x,x=tmp;
    		}
    	}
    	void work()
    	{
    		dfs(1,-1);
    		for (int j=1;1<<j<=Index;j++)
    			for (int i=1;i+(1<<j)-1<=Index;i++)
    				if(dep[f[i][j-1]]<dep[f[i+(1<<j-1)][j-1]])
    					f[i][j]=f[i][j-1];
    				else
    					f[i][j]=f[i+(1<<j-1)][j-1];
    	}
    }T;
    
    void add(int from,int to,int w)
    {
    	g[++cnt].nxt=head[from];
    	g[cnt].to=to;
    	g[cnt].w=w;
    	head[from]=cnt;
    }
    
    int read()
    {
    	char c=getchar();
    	int x=0,f=1;
    	while(c<'0'||c>'9')
    	{
    		if(c=='-')
    			f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9')
    		x=x*10+c-'0',c=getchar();
    	return x*f;
    }
    
    void init()
    {
    	log[0]=-1;
    	for (int i=1;i<=N-9;i++)
    		log[i]=log[i>>1]+1;
    	n=read(),Q=read();
    	for (rint i=1;i<n;i++)
    	{
    		int x,y,z;
    		x=read(),y=read(),z=read();
    		T.add(x,y,z),T.add(y,x,z);
    	}
    	T.work();
    }
    
    void build(int fa)
    {
    	T.del[fa]=1;
    	for (rint i=T.head[fa];i;i=T.g[i].nxt)
    	{
    		int v=T.g[i].to;
    		if(T.del[v]||v==fa)
    			continue;
    		int w=T.Get_Weight(v);
    		F[w]=fa,add(fa,w,v),add(w,fa,v);
    		build(w);
    	}
    }
    
    void Modify(int x,int y)
    {
    	//printf("eijfie %d %d
    ",x,y);
    	for (rint i=x;i;i=F[i])
    	{
    		sum[i]+=y;
    		if(i!=root)
    		{
    			LL fuck=1LL*T.Get_dis(x,F[i])*y;
    			//if(x==3&&y==1)
    				//printf("???%d %d %d
    ",x,F[i],T.Get_dis(2,3));
    			dis1[F[i]]+=fuck,dis2[i]+=fuck;
    		}
    	}
    }
    
    LL calc(int x)
    {
    	LL ans=dis1[x];
    	for (rint i=x;F[i];i=F[i])
    	{
    		ans+=dis1[F[i]]-dis2[i];
    		ans+=(sum[F[i]]-sum[i])*T.Get_dis(x,F[i]);
    	}
    	return ans;
    }
    
    LL Query(int x)
    {
    	LL last=calc(x);
    	//printf("fuck%d %d
    ",x,last);
    	for (rint i=head[x];i;i=g[i].nxt)
    	{
    		if(g[i].to==F[x])
    			continue;
    		LL now=calc(g[i].w);
    		//printf("%lld %d
    ",now,g[i].w);
    		if(now<last)
    			return Query(g[i].to);
    	}
    	return last;
    }
    
    void print(int x,int fa)
    {
    	printf("%d %d
    ",fa,x);
    	for (rint i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa)
    			continue;
    		print(v,x);
    	}
    }
    
    void work()
    {
    	root=T.Get_Weight(1);
    	build(root);
    	//printf("weoigwi%d
    ",T.LCA(2,3));
    	//print(root,-1);
    	for (rint _=1;_<=Q;_++)
    	{
    		int x,y;
    		x=read(),y=read();
    		Modify(x,y);
    		//if(_==4)
    			//printf("wyj%d
    ",dis1[2]);
    		printf("%lld
    ",Query(root));
    	}
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    C语言基础学习8:指针数组
    C语言基础学习7:返回指针值的函数
    C语言基础学习6: 指向函数的指针
    C语言基础学习5:字符串与指针
    C语言基础学习4:数组与指针
    C语言基础学习3:指针
    python 入门 之二 列表 元组 字典 字符串 集合的定义及基本操作
    python入门之路 一
    whl格式 和egg格式
    python 连接mongodb ,并将EXCEL文档导入mongodb
  • 原文地址:https://www.cnblogs.com/With-penguin/p/12724745.html
Copyright © 2011-2022 走看看