【ZJOI2008】树的统计(树链剖分模板)

原题见洛谷

这题就是树链剖分的模板,不知道是不是国内OI水平提高太快,前几年省选题都变成模板题了...

#include<bits/stdc++.h>
using namespace std;
const int MAXN=30005;
const int INF=1000000;
int MAX[MAXN*2],sum[MAXN*2],lc[MAXN*2],rc[MAXN*2];
int fa[MAXN],dep[MAXN],size[MAXN],dfs_pos[MAXN],last[MAXN],big_son[MAXN],a[MAXN],b[MAXN],top_node[MAXN];
int N,np=0,np2=0,rt=0,dfs_clock=0;
struct edge{int to,pre;}E[MAXN*2];

char c;int flag;
void scan(int &x)
{
	flag=1;
	for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
	if(c=='-') flag=-1,c=getchar();
	for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
	x*=flag;
}

char num[20];int ct;
void print(int x)
{
	ct=0;
	if(x<0) putchar('-'),x=-x;
	if(!x) num[ct++]='0';
	while(x) num[ct++]=x%10+'0',x/=10;
	while(ct--) putchar(num[ct]);
	putchar('\n');
}
//---------------------------------
void addedge(int u,int v)
{
	E[++np2]=(edge){v,last[u]};
	last[u]=np2;
}

void DFS1(int i,int f,int d)
{
	dep[i]=d; fa[i]=f; size[i]=1;
	for(int p=last[i];p;p=E[p].pre)
	{
		int j=E[p].to;
		if(j==f) continue;
		DFS1(j,i,d+1); size[i]+=size[j];
		if(size[j]>size[big_son[i]]) big_son[i]=j;
	}
}

void DFS2(int i,int top)
{
	dfs_pos[i]=++dfs_clock;
	top_node[i]=top; b[dfs_clock]=a[i];
	if(!big_son[i]) return;
	DFS2(big_son[i],top);
	for(int p=last[i];p;p=E[p].pre)
	{
		int j=E[p].to;
		if(j==fa[i]||j==big_son[i]) continue;
		DFS2(j,j);
	}
}
//-------------------------------------
void pushup(int now) 
{
	sum[now]=sum[lc[now]]+sum[rc[now]];
	MAX[now]=max(MAX[lc[now]],MAX[rc[now]]);
}

void build(int &now,int L,int R)
{
	if(!now) now=++np;
	if(L==R)
	{
		sum[now]=MAX[now]=b[L];
		return;
	}
	int mid=(L+R)/2;
	build(lc[now],L,mid);
	build(rc[now],mid+1,R);
	pushup(now);
}

void update(int now,int L,int R,int pos,int w)
{
	if(L==pos&&R==pos)
	{
		sum[now]=MAX[now]=w;
		return;
	}
	int mid=(L+R)/2;
	if(pos<=mid) update(lc[now],L,mid,pos,w);
	if(mid<pos) update(rc[now],mid+1,R,pos,w);
	pushup(now);
}

int qmax(int now,int L,int R,int i,int j)
{
	if(i<=L&&R<=j) return MAX[now];
	int mid=(L+R)/2,ans=-INF;
	if(i<=mid) ans=max(ans,qmax(lc[now],L,mid,i,j));
	if(mid<j) ans=max(ans,qmax(rc[now],mid+1,R,i,j));
	return ans;
}

int qsum(int now,int L,int R,int i,int j)
{
	if(i<=L&&R<=j) return sum[now];
	int mid=(L+R)/2,ans=0;
	if(i<=mid) ans+=qsum(lc[now],L,mid,i,j);
	if(mid<j) ans+=qsum(rc[now],mid+1,R,i,j);
	return ans;
}

int MAX_range(int u,int v)
{
	int ans=-INF;
	while(top_node[u]!=top_node[v])
	{
		if(dep[top_node[u]]<dep[top_node[v]]) swap(u,v);
		ans=max(ans,qmax(rt,1,N,dfs_pos[top_node[u]],dfs_pos[u]));
		u=fa[top_node[u]];
	}
	if(dep[u]>dep[v]) swap(u,v);
	return max(ans,qmax(rt,1,N,dfs_pos[u],dfs_pos[v]));
}

int SUM_range(int u,int v)
{
	int ans=0;
	while(top_node[u]!=top_node[v])
	{
		if(dep[top_node[u]]<dep[top_node[v]]) swap(u,v);
		ans+=qsum(rt,1,N,dfs_pos[top_node[u]],dfs_pos[u]);
		u=fa[top_node[u]];
	}
	if(dep[u]>dep[v]) swap(u,v);
	return ans+qsum(rt,1,N,dfs_pos[u],dfs_pos[v]);
}

int main()
{
	int Q,i,u,v,w;
	scan(N);
	for(i=1;i<N;i++)
	{
		scan(u);scan(v);
		addedge(u,v);
		addedge(v,u);
	}
	for(i=1;i<=N;i++) scan(a[i]);
	DFS1(1,0,1); DFS2(1,1); build(rt,1,N);
	scan(Q); char op[10];
	while(Q--)
	{
		scanf("%s",op);
		if(op[0]=='C')
		{
			scan(u);scan(w);
			update(rt,1,N,dfs_pos[u],w);
		}
		else if(op[1]=='M')
		{
			scan(u);scan(v);
			print(MAX_range(u,v));
		}
		else
		{
			scan(u);scan(v);
			print(SUM_range(u,v));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/81660233