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++ string中find() ,rfind() 等函数 用法总结及示例
    UVA 230 Borrowers (STL 行读入的处理 重载小于号)
    UVA 12100 打印队列(STL deque)
    uva 12096 The SetStack Computer(STL set的各种库函数 交集 并集 插入迭代器)
    uva 1592 Database (STL)
    HDU 1087 Super Jumping! Jumping! Jumping!
    hdu 1176 免费馅饼
    HDU 1003 Max Sum
    转战HDU
    hust 1227 Join Together
  • 原文地址:https://www.cnblogs.com/With-penguin/p/12758271.html
Copyright © 2011-2022 走看看