zoukankan      html  css  js  c++  java
  • luogu P3676 小清新数据结构题

    首先我们考虑如果题目要求的不是子树平方和而是子树和,也就是(sum_{i=1}^{n}siz[i]),那么每个点的贡献就是他到根的距离加一,所以答案也可以写成:
    (sum_{i=1}^{n}a[i] imes dis(i,p)+Sum)(其中(p)表示当前的根,(a[i])表示点(i)的点权,(Sum=sum a[i]))。
    我们发现这个东西其实就是P3345 [ZJOI2015]幻想乡战略游戏这个题,为了后文柿子的表达方便,我们记
    (calc(p)=sum_{i=1}^{n}a[i] imes dis(i,p))

    然后这个平方很不好处理。首先给出一个结论,无论根在哪里,(sum_{i=1}^{n}siz[i] imes (Sum-siz[i]))的值恒定(记这个常量为(W))。

    怎么证明呢,发现任意两点(i,j)对上述式子的贡献是(a[i] imes a[j] imes dis(i,j)),这个东西无论根在哪里都不会变的。

    然后稍微变形一下就能推出(sum siz[i]^2=Sum imes (calc(p)+Sum) - W)。所以我们可以在根为(1)的时候求出(W)然后动态点分治维护(calc(p))就好了。

    现在的问题就是如何维护。除了(W)以外其他都是非常好维护的,我们发现一个节点(k)(W)的贡献为
    (a[k] imes sum_{i=1}^{n}a[i] imes dis(i,k)=a[k] imes calc(k)),然后对于怎么维护(W)就不用多说了吧。。。

    代码:

    #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],a[N];
    LL dis1[N],dis2[N],sum[N],W,Sum;
    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;
    	struct Edge
    	{
    		int nxt,to;
    	}g[N*2];
    	
    	void add(int from,int to)
    	{
    		g[++cnt].nxt=head[from];
    		g[cnt].to=to;
    		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;
    			dfs(v,x);
    			Euler[++Index]=x,f[Index][0]=x;
    		}
    	}
    	int Get_dis(int x,int y)
    	{
    		return dep[x]+dep[y]-2*dep[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];
    	}
    	void dfs_1(int x,int fa)
    	{
    		siz[x]=a[x];
    		for (int i=head[x];i;i=g[i].nxt)
    		{
    			int v=g[i].to;
    			if(v==fa)
    				continue;
    			dfs_1(v,x);
    			siz[x]+=siz[v];
    		}
    	}
    }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;
    		x=read(),y=read();
    		T.add(x,y),T.add(y,x);
    	}
    	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)
    {
    	for (rint i=x;i;i=F[i])
    	{
    		sum[i]+=y;
    		if(i!=root)
    		{
    			LL fuck=1LL*T.Get_dis(x,F[i])*y;
    			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;
    }
    
    void work()
    {
    	root=T.Get_Weight(1);
    	build(root);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]),Modify(i,a[i]),Sum+=a[i];
    	T.dfs_1(1,-1);
    	for (int i=1;i<=n;i++)
    		W+=(Sum-T.siz[i])*T.siz[i];
    	for (rint _=1;_<=Q;_++)
    	{
    		int x,y,opt;
    		opt=read();
    		if(opt==1)
    		{
    			x=read(),y=read();
    			int delx=y-a[x];
    			W+=calc(x)*delx,Sum+=delx;
    			Modify(x,delx);
    			a[x]=y;
    		}
    		else
    		{
    			x=read();
    			printf("%lld
    ",Sum*(Sum+calc(x))-W);
    		}
    	}
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    C#---将数据库数据转换为json格式
    ASP.NET ---根据值让树中某一节点选中
    SQL---查询树中某个节点及其所有子节点
    CSS---相对定位笔记
    CSS---绝对定位笔记
    滑雪
    Self Numbers
    Lotto
    Parencodings
    Robot Motion
  • 原文地址:https://www.cnblogs.com/With-penguin/p/12758271.html
Copyright © 2011-2022 走看看