BZOJ 1036([ZJOI2008]树的统计Count-树链剖分[成熟版])

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 3205   Solved: 1335
[ Submit][ Status]

Description

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

输入的第一行为一个整数n,表示节点的个数。 接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。 接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。 接下来1行,为一个整数q,表示操作的总数。 接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

Sample Output

4
1
2
2
10
6
5
6
5
16



在yzc的RP++模板下:

我完成了成熟版的树链剖分

本次更新的主要内容:

1.趋向于把值存在点上

2.引入了dfs序的概念

3.成功的只建一棵线段树,从此和可持久化说再见


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (30000+10)
#define MAXM (200000+10)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
int n,m;
ll sum[MAXN<<3]={0},maxv[MAXN<<3]={0};
void update(int x){sum[x]=sum[Lson]+sum[Rson],maxv[x]=max(maxv[Lson],maxv[Rson]);}
void change(int x,int l,int r,int L,int c)
{	
	if (l==r) {sum[x]=maxv[x]=c;return;}
	int m=l+r>>1;
	if (L<=m) change(Lson,l,m,L,c);
	else change(Rson,m+1,r,L,c);
	update(x);
}
ll qurrysum(int x,int l,int r,int L,int R)
{
	if (L<=l&&r<=R) return sum[x];
	int m=l+r>>1;
	ll ans=0;
	if (L<=m) ans+=qurrysum(Lson,l,m,L,R);
	if (m<R) ans+=qurrysum(Rson,m+1,r,L,R);
	return ans;
}
ll qurrymax(int x,int l,int r,int L,int R)
{
	if (L<=l&&r<=R) return maxv[x];
	int m=l+r>>1;
	ll ans=-INF;
	if (L<=m) ans=max(ans,qurrymax(Lson,l,m,L,R));
	if (m<R) ans=max(ans,qurrymax(Rson,m+1,r,L,R));
	return ans;
}
int edge[MAXN*2],pre[MAXN]={0},next[MAXN*2]={0},size=0;
void addedge(int u,int v)
{
	edge[++size]=v;
	next[size]=pre[u];
	pre[u]=size;
}
void addedge2(int u,int v){addedge(u,v),addedge(v,u);}
int dep[MAXN]={0},siz[MAXN]={0},opt[MAXN]={0},father[MAXN]={0};
void dfs(int x)
{
	siz[x]=1;
	dep[x]=dep[father[x]]+1;
	Forp(x)
	{
		int &v=edge[p];
		if (v^father[x])
		{
			father[v]=x;
			dfs(v);
			siz[x]+=siz[v];
			if (siz[v]>siz[opt[x]]) opt[x]=v;
		}
	}
}
int top[MAXN],w[MAXN],place[MAXN],tim=0;
void dfs2(int x,int chain)
{
	top[x]=chain;
	place[x]=++tim;
	change(1,1,n,place[x],w[x]);
	if (opt[x]) dfs2(opt[x],chain);else return;
	Forp(x)
	{
		int &v=edge[p];
		if (v^father[x]&&v^opt[x])
		{
			dfs2(v,v);
		}
	}
}
ll lca_sum(int u,int v)
{
	ll ans=0;
	while (top[u]^top[v])
	{
		if (dep[top[u]]<dep[top[v]]) swap(u,v);
		ans+=qurrysum(1,1,n,place[top[u]],place[u]);
		u=father[top[u]];
	}
	if (dep[u]<dep[v]) swap(u,v);
	ans+=qurrysum(1,1,n,place[v],place[u]);
	return ans;
}
ll lca_max(int u,int v)
{
	ll ans=-INF;
	while (top[u]^top[v])
	{
		if (dep[top[u]]<dep[top[v]]) swap(u,v);
		ans=max(ans,qurrymax(1,1,n,place[top[u]],place[u]));
		u=father[top[u]];
	}
	if (dep[u]<dep[v]) swap(u,v);
	ans=max(ans,qurrymax(1,1,n,place[v],place[u]));
	return ans;
}
char c[10];
int main()
{
//	freopen("bzoj1036.in","r",stdin);
	scanf("%d",&n);
	/*
	For(i,n)
	{
		int p,l,r,c;
		cin>>p>>l>>r;
		if (p==1) change(1,1,n,l,r);
		if (p==2) cout<<qurrysum(1,1,n,l,r)<<endl;
		if (p==3) cout<<qurrymax(1,1,n,l,r)<<endl;
		
	}*/
	For(i,n-1) 
	{
		int u,v;
		scanf("%d%d",&u,&v);
		addedge2(u,v);
	}
	For(i,n) scanf("%d",&w[i]);
	dfs(1);
	dfs2(1,1);
	scanf("%d",&m);
	For(i,m)
	{
		int a,b;
		scanf("%s%d%d",c,&a,&b);
		switch(c[1])
		{
			case'H':change(1,1,n,place[a],b);break;
			case'S':printf("%lld\n",lca_sum(a,b));break;
			case'M':printf("%lld\n",lca_max(a,b));
		}
	}
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值