bzoj3589 动态树

3589: 动态树

Time Limit: 30 Sec  Memory Limit: 1024 MB

Submit: 288  Solved: 109

[Submit][Status][Discuss]

Description

别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件

事件0:

这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.

事件1:

小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.

Input

第一行一个整数n(1<=n<=200,000), 即节点数.

接下来n-1行, 每行两个数字u, v. 表示果子u和果子v之间有一条直接的边. 节点从1开始编号.

在接下来一个整数nQ(1<=nQ<=200,000), 表示事件.

最后nQ行, 每行开头要么是0, 要么是1.

如果是0, 表示这个事件是事件0. 这行接下来的2个整数u, delta表示以u为根的子树中的每个节点长出了delta个果子.

如果是1, 表示这个事件是事件1. 这行接下来一个整数K(1<=K<=5), 表示这次询问涉及K个树枝. 接下来K对整数u_k, v_k, 每个树枝从节点u_k到节点v_k. 由于果子数可能非常多, 请输出这个数模2^31的结果.

Output

对于每个事件1, 输出询问的果子数.

Sample Input

5

1 2

2 3

2 4

1 5

3

0 1 1

0 2 3

1 2 3 1 1 4

Sample Output

13

HINT

1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.

生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.

Source

By 佚名提供

子树修改和区间并的查询,树链剖分+线段树可以解决。

查询操作只需将链上的点打上标记,最终输出所有标记的点的权值和,注意每次询问后都要去除所有标记。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 200005
using namespace std;
struct edge{int next,to;}e[maxn*2];
struct seg{int l,r,sum,tag[2],ret;}t[maxn*4];
int n,m,x,y,cnt,tot,opt;
int l[maxn],r[maxn],d[maxn];
int fa[maxn],sz[maxn],son[maxn],head[maxn],belong[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y)
{
	e[++cnt]=(edge){head[x],y};head[x]=cnt;
	e[++cnt]=(edge){head[y],x};head[y]=cnt;
}
inline void dfs1(int x)
{
	sz[x]=1;
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if (sz[y]) continue;
		d[y]=d[x]+1;
		fa[y]=x;
		dfs1(y);
		sz[x]+=sz[y];
		if (sz[y]>sz[son[x]]) son[x]=y;
	}
}
inline void dfs2(int x,int chain)
{
	l[x]=++tot;belong[x]=chain;
	if (son[x]) dfs2(son[x],chain);
	for(int i=head[x];i;i=e[i].next)
		if (!l[e[i].to]&&e[i].to!=son[x]) dfs2(e[i].to,e[i].to);
	r[x]=tot;
}
inline void pushup(int k)
{
	t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
	t[k].ret=t[k<<1].ret+t[k<<1|1].ret;
}
inline void build(int k,int l,int r)
{
	t[k].l=l;t[k].r=r;t[k].tag[0]=-1;
	if (l==r) return;
	int mid=(l+r)>>1;
	build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline void update(int k,int z)
{
	t[k].tag[1]+=z;
	t[k].sum+=z*(t[k].r-t[k].l+1);
}
inline void update2(int k,int z)
{
	t[k].tag[0]=z;
	t[k].ret=t[k].sum*z;
}
inline void pushdown(int k)
{
	if (t[k].tag[1])
	{
		update(k<<1,t[k].tag[1]);
		update(k<<1|1,t[k].tag[1]);
		t[k].tag[1]=0;
	}
	if (t[k].tag[0]!=-1)
	{
		update2(k<<1,t[k].tag[0]);
		update2(k<<1|1,t[k].tag[0]);
		t[k].tag[0]=-1;
	}
}
inline void change(int k,int x,int y,int z)
{
	if (t[k].tag[0]==z) return;
	if (t[k].l==x&&t[k].r==y){update2(k,z);return;}
	int mid=(t[k].l+t[k].r)>>1;
	pushdown(k);
	if (y<=mid) change(k<<1,x,y,z);
	else if (x>mid) change(k<<1|1,x,y,z);
	else{change(k<<1,x,mid,z);change(k<<1|1,mid+1,y,z);}
	pushup(k);
}
inline void add(int k,int x,int y,int z)
{
	if (t[k].l==x&&t[k].r==y){update(k,z);return;}
	int mid=(t[k].l+t[k].r)>>1;
	pushdown(k);
	if (y<=mid) add(k<<1,x,y,z);
	else if (x>mid) add(k<<1|1,x,y,z);
	else{add(k<<1,x,mid,z);add(k<<1|1,mid+1,y,z);}
	pushup(k);
}
inline void solve(int x,int y,int z)
{
	while (belong[x]!=belong[y])
	{
		if (d[belong[x]]<d[belong[y]]) swap(x,y);
		change(1,l[belong[x]],l[x],z);
		x=fa[belong[x]];
	}
	if (d[x]>d[y]) swap(x,y);
	change(1,l[x],l[y],z);
}
int main()
{
	n=read();
	F(i,1,n-1) add_edge(read(),read());
	d[1]=1;dfs1(1);dfs2(1,1);
	build(1,1,n);
	m=read();
	while(m--)
	{
		opt=read();x=read();
		if (opt)
		{
			F(i,1,x) solve(read(),read(),1);
			printf("%d\n",t[1].ret&((1<<31)-1));
			update2(1,0);
		}
		else add(1,l[x],r[x],read());
	}
}
时间: 2024-08-07 00:15:19

bzoj3589 动态树的相关文章

树链剖分 BZOJ3589 动态树

3589: 动态树 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 543  Solved: 193[Submit][Status][Discuss] Description 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝

bzoj千题计划214:bzoj3589: 动态树

http://www.lydsy.com/JudgeOnline/problem.php?id=3589 树链剖分 用线段数维护扫描线的方式来写,标记只打不下传 #include<cstdio> #include<iostream> #include<algorithm> #define N 200001 using namespace std; int n; int front[N],to[N<<1],nxt[N<<1],tot; int si

BZOJ3589动态树

**错误改了一上午. 先做熟练泼粪 k<=5,因此我们可以模拟这个过程,在线段树上把标记建出来然后pushup时候更新就好了. By:大奕哥 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=200005; 4 struct tree{ 5 int l,lz,ll;long long s,ret; 6 }t[N<<2]; 7 int head[N],cnt,n,id,bel[N],pos[N],siz

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)

3589: 动态树 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 405  Solved: 137[Submit][Status][Discuss] Description 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝

luoguP3690 【模板】Link Cut Tree (动态树)[LCT]

题目背景 动态树 题目描述 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接. 2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在. 3:后接两个整数(x,y),代表将点X上的权值变成Y. 输入输出格式 输入格式: 第1行两个整数,分别为N和M,代表点数和操

bzoj 2631: tree 动态树+常数优化

2631: tree Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1716  Solved: 576[Submit][Status] Description 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一:+ u v c:将u到v的路径上的点的权值都加上自然数c:- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树:* u v c:将u到v的

动态树 Link-Cut Trees

动态树 动态树问题, 即要求我们维护一个由若干棵子结点无序的有根树组成的森林. 要求这个数据结构支持对树的分割.合并,对某个点到它的根的路径的某些操作,以及对某个点的子树进行的某些操作. 在这里我们考虑一个简化的动态树问题,它只包含对树的形态的操作和对某个点到根的路径的操作: 维护一个数据结构,支持以下操作: • MAKE TREE() — 新建一棵只有一个结点的树. • CUT(v) — 删除 v 与它的父亲结点 parent(v) 的边,相当于将点 v 的子树分离了出来. • JOIN(v,

extjs动态树 动态grid 动态列

由于项目需要做一个动态的extjs树.列等等,简而言之,就是一个都是动态的加载功能, 自己琢磨了半天,查各种资料,弄了将近两个星期,终于做出来了 首先,想看表结构,我的这个功能需要主从两张表来支持 代码目录表: CREATE TABLE SYS_T01_CODECONTENT ( ID NUMBER NOT NULL, PID NUMBER NOT NULL, TABLENAME VARCHAR2(50 BYTE), ZH_CN VARCHAR2(200 BYTE), ENABLE CHAR(1