• 【BZOJ3730】震波(点分树)


    点此看题面

    大致题意: 给你一棵树,每个节点有一个权值,需要实现两种操作:求与节点(x)距离不超过(k)的所有点的权值和;单点修改。(强制在线)

    前言

    我还是太弱了。。。

    先想这道题各种复杂的细节想了半天,总共码了一个多小时。

    然后,交上去又是(RE)又是(TLE),看到这是强制在线的题目,自然而然以为自己(WA)了。

    先去吃了个午饭,接着心态爆炸地调了半个小时之后——

    原来,我是真的(RE)了。。。(不用说,又是一个智障错误)

    点分树

    什么是点分树?

    我在这篇博客里有过简单的提及:再学点分治——动态点分治

    现在,相当于是重拾动态点分治了吧。

    大致想法

    考虑对于每个点,我们记下它在点分树上所有祖先以及到每一个祖先的距离(一个节点最多只有(logN)个祖先)。

    然后,我们开两个树状数组,一个维护子树内到其距离小于等于(k)的元素和,一个维护在它子树内的节点对父节点的贡献。(注意,这里需要开(vector),否则就会爆内存。)

    为什么要这么复杂呢?因为点分树并不是真正的树,一个点到父节点的父节点的距离,甚至可能小于它到父节点的距离,所以不这样维护一些就会变得超级麻烦。

    对于修改,我们只要修改其到根的路径上所有节点的两个树状数组。

    对于询问,要注意不能重复,即计算父节点答案时要减去子节点子树内的贡献,这也正是开两个树状数组的原因。

    大致想法就是这么简单,只不过写起来要麻烦多了而已。。。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    #define pb push_back
    using namespace std;
    int n,a[N+5],ee,lnk[N+5];struct edge {int to,nxt;}e[N<<1];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Tp I void writeln(Con Ty& x) {write(x),pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    class TreeArray//树状数组
    {
    	private:
    		int n;vector<int> a;//注意开vector
    	public:
    		I void Set(CI x) {n=x,a.resize(x+1);}I void U(RI x,CI v) {W(x<=n) a[x]+=v,x+=x&-x;}
    		I int Q(RI x,RI t=0) {x>n&&(x=n);W(x) t+=a[x],x-=x&-x;return t;}
    };
    class DotSolveTree//点分树
    {
    	private:
    		int Rt,Sz[N+5],Mx[N+5],used[N+5],dis[N+5],T,S[N+5],P[N+5];
    		TreeArray V[N+5],G[N+5];vector<int> f[N+5],d[N+5];
    		I void GetRt(CI x,RI s,CI lst=0)//找重心
    		{
    			Sz[x]=1,Mx[x]=0;for(RI i=lnk[x];i;i=e[i].nxt) !used[e[i].to]&&
    				e[i].to^lst&&(GetRt(e[i].to,s,x),Sz[x]+=Sz[e[i].to],Gmax(Mx[x],Sz[e[i].to]));
    			Gmax(Mx[x],s-Sz[x]),Mx[x]<Mx[Rt]&&(Rt=x);
    		}
    		I int GetDis(CI x,CI lst=0,CI d=0)//求出到当前点最远的距离
    		{
    			RI i,t,Mx=d;for(i=lnk[x];i;i=e[i].nxt) !used[e[i].to]&&
    				e[i].to^lst&&(dis[e[i].to]=d+1,t=GetDis(e[i].to,x,d+1),Gmax(Mx,t));
    			return Mx;
    		}
    		I void dfs(CI x,CI lst=0)//遍历路径记录信息
    		{
    			++T,S[T]=dis[P[T]=x];for(RI i=lnk[x];i;i=e[i].nxt)
    				!used[e[i].to]&&e[i].to^lst&&(dfs(e[i].to,x),0);
    		}
    		I void Work(RI x)
    		{
    			RI i,Mx=GetDis(x);V[x].Set(Mx);
    			for(used[x]=1,i=lnk[x];i;i=e[i].nxt) if(!used[e[i].to])
    			{
    				Rt=0,GetRt(e[i].to,Sz[e[i].to]),dfs(Rt),G[Rt].Set(Mx);
    				W(T) V[x].U(S[T],a[P[T]]),G[Rt].U(S[T],a[P[T]]),f[P[T]].pb(x),d[P[T]].pb(S[T]),--T;//计算贡献
    				Work(Rt);//继续处理子树,注意这句话要放后面
    			}
    		}
    	public:
    		I void Build()//建树
    		{
    			Mx[Rt=0]=1e9,GetRt(1,n),Work(Rt);
    			for(RI i=1;i<=n;++i) reverse(f[i].begin(),f[i].end()),reverse(d[i].begin(),d[i].end());//注意这两个数组存下来的顺序是反的,故应翻转
    		}
    		I void Upt(CI x,CI v)//修改
    		{
    			if(!f[x].size()) return;//注意这句话,就是因为没有它,害得我RE了
    			G[x].U(d[x][0],v);for(RI i=0,sz=f[x].size();i^sz;++i)
    				V[f[x][i]].U(d[x][i],v),i^(sz-1)&&(G[f[x][i]].U(d[x][i+1],v),0);
    		}
    		I int Qry(CI x,CI k)//询问
    		{
    			RI t=a[x]+V[x].Q(k);for(RI i=0,sz=f[x].size();i^sz;++i) d[x][i]<=k&&
    				(t+=a[f[x][i]]+V[f[x][i]].Q(k-d[x][i])-G[i?f[x][i-1]:x].Q(k-d[x][i]));//此处应防止算重
    			return t;
    		}
    }T;
    int main()
    {
    	RI Qt,i,op,x,y,lst=0;for(F.read(n),F.read(Qt),i=1;i<=n;++i) F.read(a[i]);
    	for(i=1;i^n;++i) F.read(x),F.read(y),add(x,y),add(y,x);T.Build();
    	W(Qt--) F.read(op),F.read(x),F.read(y),x^=lst,y^=lst,
    		op?(T.Upt(x,y-a[x]),a[x]=y):(F.writeln(lst=T.Qry(x,y)),0);
    	return F.clear(),0;
    }
    
  • 相关阅读:
    HBase性能调优
    HBase原理和设计
    HBase 架构脑图
    Hadoop
    Hadoop YARN架构设计要点
    Hadoop-YARN
    Hadoop-HDFS
    TCP传输
    分布式系统常见的事务处理机制
    Zookeeper Client简介
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3730.html
Copyright © 2020-2023  润新知