• HDU 4918 Query on the subtree(动态点分治+树状数组)


    题意

    给定一棵 (n) 个节点的树,每个节点有点权。完成 (q) 个操作——操作分两种:修改点 (x) 的点权、查询与 (x) 距离小于等于 (d) 的权值总和。

    (1 leq n,q leq 10^5)

    思路

    从最简单的情况分析——只有一次查询。当然一遍 (O(n))( ext{dfs}) 可以直接写,不过要用点分治写的话,( ext{solve}) 函数直接容斥一下就可以了。

    如果多个询问呢?其实在回答关于点 (x) 的询问时,其实只需要计算管辖 (x) 的所有重心的答案。我们只需要将点分治的过程记录下来,查询只查管辖 (x) 的重心,就可以在 (log n) 的复杂度内回答一次询问了。

    具体的实现每道题略有区别,但具体思路大致相同。别忘了我们是从一次查询作优化,那么我们对于一个点,记录它到重心的距离;对于每个重心开一个数组,表示管辖范围内距离为 (d) 的节点权值总和,然后前缀和一下就变成了距离小于等于 (d) 的权值总和,由于还有容斥的部分,故符号也要记录。若节点 (x) 询问为 (d) ,对于某一级重心 (C) ,距离为 (dis) ,对应前缀和数组 (A) ,对应符号为 (s (sin{1,-1})) ,那么 (x)(C) 的贡献就是 (scdot A[d-dis])

    而带上修改其实也没什么区别,只要把前缀和换成树状数组,然后每次修改,对于某一级重心 (C) ,在树状数组的 (dis) 位置做修改即可。

    动态点分治就是把点分治的过程用适当容器去维护的算法。

    代码

    #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)
    typedef long long LL;
    using namespace std;
    const int N=1e5+5;
    template<const int maxn,const int maxm>struct Linked_list
    {
    	int head[maxn],to[maxm],nxt[maxm],tot;
    	Linked_list(){clear();}
    	void clear(){memset(head,-1,sizeof(head));tot=0;}
    	void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
    	#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
    };
    struct FenwickTree
    {
    	#define lowbit(x) ((x)&-(x))
    	vector<int>c;int n;
    	void build(int _n){c.clear();FOR(i,0,n=_n+1)c.push_back(0);}
    	void update(int k,int val){for(k++;k<=n;k+=lowbit(k))c[k]+=val;}
    	int query(int k){int res=0;for(k=min(k+1,n);k>0;k^=lowbit(k))res+=c[k];return res;}
    	#undef lowbit
    };
    Linked_list<N,N<<1>G;
    FenwickTree FT[N*2];int Fc;
    int Fid[N][45],dis[N][45],lv[N];bool sgn[N][45];
    int sz[N];bool mark[N];
    int pw[N],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(res<Mi)C=u,Mi=res;
    }
    void dfs_init(int u,int f,int D,bool s)
    {
    	Fid[u][++lv[u]]=Fc,dis[u][lv[u]]=D,sgn[u][lv[u]]=s;
    	EOR(i,G,u)
    	{
    		int v=G.to[i];
    		if(v==f||mark[v])continue;
    		dfs_init(v,u,D+1,s);
    	}
    }
    int dfs_dep(int u,int f,int d)
    {
    	int res=d;
    	EOR(i,G,u)
    	{
    		int v=G.to[i];
    		if(v==f||mark[v])continue;
    		res=max(res,dfs_dep(v,u,d+1));
    	}
    	return res;
    }
    void dac(int u,int tot)
    {
    	int Mi=1e9;
    	CFS(u,0,tot,u,Mi);
    	mark[u]=1;
    	FT[++Fc].build(dfs_dep(u,0,0));
    	dfs_init(u,0,0,1);
    	EOR(i,G,u)
    	{
    		int v=G.to[i];
    		if(mark[v])continue;
    		FT[++Fc].build(dfs_dep(v,u,1));
    		dfs_init(v,u,1,0);
    		dac(v,sz[u]>sz[v]?sz[v]:tot-sz[u]);
    	}
    }
    
    void update(int u,int val)
    {
    	FOR(i,1,lv[u])
    	{
    		int v=Fid[u][i],w=dis[u][i];
    		FT[v].update(w,val);
    	}
    }
    int query(int u,int d)
    {
    	int res=0;
    	FOR(i,1,lv[u])
    	{
    		int v=Fid[u][i],w=dis[u][i];bool s=sgn[u][i];
    		if(s)res+=FT[v].query(d-w);
    		else res-=FT[v].query(d-w);
    	}
    	return res;
    }
    
    int main()
    {
    	while(~scanf("%d%d",&n,&q))
    	{
    		G.clear();
    		FOR(i,1,n)scanf("%d",&pw[i]);
    		FOR(i,1,n-1)
    		{
    			int u,v;
    			scanf("%d%d",&u,&v);
    			G.add(u,v),G.add(v,u);
    		}
    		Fc=0;
    		memset(lv,0,sizeof(lv));
    		memset(mark,0,sizeof(mark));
    		dac(1,n);
    		FOR(i,1,n)update(i,pw[i]);
    		while(q--)
    		{
    			char str[5];int x,y;
    			scanf("%s%d%d",str,&x,&y);
    			if(str[0]=='!')
    			{
    				update(x,y-pw[x]);
    				pw[x]=y;
    			}
    			else if(str[0]=='?')printf("%d
    ",query(x,y));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    java注解
    SpringBoot 整合 MybatisPlus 3.0
    第三章 列表简介
    第二章 变量及简单数据类型
    收藏通俗知识
    2017.8.13 列标,元组,字符串
    Python入门--4--分之和循环
    Python入门---易错已错易混淆----知识点
    Perl语言入门--4--函数
    perl学习之精髓中的精髓
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10188484.html
Copyright © 2020-2023  润新知