zoukankan      html  css  js  c++  java
  • 树链剖分笔记(轻重链剖分)

    我今天居然一次提交就A了!惊喜!

    树链剖分可以在树上维护点的权值,可以进行一条链上的求和和修改操作,也可以将一个子树进行求和和修改。

    我们的具体做法是要将这个树放到一个序列里,然后使用线段树来维护它。

    我们定义重链和轻链,重链是指一个节点连向它最重的子节点的边,我们可以发现我们将相连的重链看做一条重链。

    我们可以将一颗树拆分成轻链和重链,优先dfs重链,可以使得一条重链的dfs序是连续的,所以重链在线段树上也是一段连续的区间。

    我们来找两个点的最近公共祖先,通过重链来向上跳,可以找到两个点的LCA,由于跳的都是重链,可以线段树区间维护一下。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    #define mid (l+r>>1)
    #define B printf("!");
    using namespace std;
    
    int read()
    {
    	int a = 0,x = 1;
    	char ch = getchar();
    	while(ch > '9' || ch < '0'){
    		if(ch == '-') x = -1;
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9'){
    		a = a*10 + ch-'0';
    		ch = getchar();
    	}
    	return a*x;
    }
    const int N=1e6+7;
    int n,m,r,p;
    int arr[N];
    
    int head[N],go[N],nxt[N],cnt;
    void add(int u,int v)
    {
    	go[++cnt] = v;
    	nxt[cnt] = head[u];
    	head[u] = cnt;
    }
    int siz[N],son[N],dfn[N],dis[N],str[N],pos[N],fa[N];
    
    void dfs1(int u)
    {
    	siz[u] = 1;
    	for(int e = head[u];e;e = nxt[e]){
    		int v = go[e];
    		if(v == fa[u]) continue;
    		dis[v] = dis[u] + 1;
    		fa[v] = u;
    		dfs1(v);
    		if(siz[v] > siz[son[u]]) son[u] = v;
    		siz[u] += siz[v];
    	}
    }
    
    void dfs2(int u,int h)
    {
    	str[u] = h;
    	dfn[u] = ++cnt;
    	pos[cnt] = u;
    	if(son[u]) dfs2(son[u],h);
    	for(int e = head[u];e;e = nxt[e]){
    		int v = go[e];
    		if(v == fa[u] || v == son[u]) continue;
    		dfs2(v,v);
    	}
    }
    
    int lazy[N],tre[N];
    
    void build(int root,int l,int r)
    {
    	if(l == r) {tre[root] = arr[pos[l]];return;}
    	build(root<<1,l,mid);build(root<<1|1,mid+1,r);
    	tre[root] = (tre[root<<1]+tre[root<<1|1]) % p;
    }
    
    void push_down(int root,int l,int r)
    {
    	(tre[root<<1] += (mid-l+1)*lazy[root]%p)%=p,(tre[root<<1|1] += (r-mid)*lazy[root]%p)%=p;
    	(lazy[root<<1] += lazy[root])%=p,(lazy[root<<1|1] += lazy[root])%=p;
    	lazy[root] = 0;
    }
    
    void modify(int root,int l,int r,int ql,int qr,int x)
    {
    	if(l >= ql && r <= qr) {(tre[root] += (r-l+1)*x%p)%=p,(lazy[root] += x)%=p;return;}
    	if(l > qr || r < ql) return;
    	push_down(root,l,r);
    	modify(root<<1,l,mid,ql,qr,x);modify(root<<1|1,mid+1,r,ql,qr,x);
    	tre[root] = (tre[root<<1] + tre[root<<1|1])%p;
    }
    
    int query(int root,int l,int r,int ql,int qr)
    {
    	if(l >= ql && r <= qr) return tre[root];
    	if(l > qr || r < ql) return 0;
    	push_down(root,l,r);
    	return (query(root<<1,l,mid,ql,qr)+query(root<<1|1,mid+1,r,ql,qr))%p;
    }
    
    
    void LCA_updata(int u,int v,int x)
    {
    	while(str[u] != str[v]){
    //		printf("%d %d
    ",u,v);
    		if(dis[str[u]] < dis[str[v]]) swap(u,v);
    		modify(1,1,n,dfn[str[u]],dfn[u],x);
    		u = fa[str[u]];
    	}
    	if(dis[u] > dis[v]) swap(u,v);
    	modify(1,1,n,dfn[u],dfn[v],x);
    }
    
    void LCA_query(int u,int v)
    {
    	int ret = 0;
    	while(str[u] != str[v]){
    		if(dis[str[u]] < dis[str[v]]) swap(u,v);
    		(ret += query(1,1,n,dfn[str[u]],dfn[u])) %= p;
    		u = fa[str[u]];
    	}
    	if(dis[u] > dis[v]) swap(u,v);
    	(ret += query(1,1,n,dfn[u],dfn[v])) %= p;
    	printf("%d
    ",ret);
    }
    
    void tre_updata(int u,int x)
    {
    	modify(1,1,n,dfn[u],dfn[u]+siz[u]-1,x);
    }
    
    void tre_query(int u)
    {
    	int ret = query(1,1,n,dfn[u],dfn[u]+siz[u]-1);
    	printf("%d
    ",ret);
    }
    int main()
    {
    //	freopen("in.in","r",stdin);
    //	freopen("out.out","w",stdout);
    	n = read(),m = read(),r = read(),p = read();
    	for(int i = 1;i <= n;i ++) arr[i] = read();
    	for(int i = 1;i < n;i ++){
    		int u = read(),v = read();
    		add(u,v);add(v,u);
    	}
    	cnt = 0;
    	dfs1(r);dfs2(r,r);
    
    	build(1,1,n);
    
    	for(int i = 1;i <= m;i ++){
    		int op = read();
    		if(op == 1){
    			int x = read(),y = read(),z = read();
    			LCA_updata(x,y,z);
    		} else if(op == 2) {
    			int x = read(),y = read();
    			LCA_query(x,y);
    		} else if(op == 3) {
    			int x = read(),z = read();
    			tre_updata(x,z);
    		} else if(op == 4) {
    			int x = read();
    			tre_query(x);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    怎样使用 Apache ab 以及 OneAPM 进行压力測试?
    opencv之haar特征+AdaBoos分类器算法流程(三)
    分区函数Partition By的与row_number()的用法以及与排序rank()的用法详解(获取分组(分区)中前几条记录)
    REST API 调用 方法
    WebApi的安全性及其解决方案
    使用Topshelf创建Windows服务
    LINQ查询操作符之First、FirstOrDefault、Last、LastOrDefault、ElementAt、ElementAtOrDefault、Contains、Any、All、Count
    sqlbulkcopy 多表批量保存
    C#使用HttpWebRequest和HttpWebResponse上传文件示例
    C#模拟客户端发送数据示例
  • 原文地址:https://www.cnblogs.com/nao-nao/p/13651390.html
Copyright © 2011-2022 走看看