【浙江省选2008】/BZOJ1036 树的统计

                                                树的统计

题目描述

一棵树上有 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 本身。

输入格式

输入第一行为一个整数 n ,表示节点的个数。
接下来 n–1 行,每行 2 个整数 a 和 b ,表示节点 a 和节点 b 之间有一条边相连。
接下来 n 行,每行一个整数,第 i 行的整数 wi 表示节点 i 的权值。
接下来 1 行,为一个整数 q ,表示操作的总数。
接下来 q 行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

输出格式

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

样例数据 1

输入  [复制]


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

输出





10 




16

备注

【数据范围】
对于 100% 的数据,保证1<=n<=30000;0<=q<=200000;中途操作中保证每个节点的权值 w 在 -30000 到 30000 之间。

解析:

        树链剖分模板题。 

代码:

#include <bits/stdc++.h>
using namespace std;

const int Max=30010;
int n,m,ans=0,s=0,tot=0,q,SUM,MAX;
int first[Max],size[Max];
//rev[i]表示点i在线段树中的编号  seg[i]表示在线段树中i号点所对应树中的点
//top[i]表示树中的点i所在重链的最浅点,son[i]表示树中以点i的重儿子
int top[Max],depth[Max],rev[Max],seg[Max],num[Max],father[Max],son[Max];
struct bian{int to,next;};
bian edge[Max<<1];
struct shu{int maxx,sum;};
shu tree[Max<<2];

inline int get_int()    //读入优化
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') {f=-1;c=getchar();}
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline int mx(int x,int y)    //相当于max(x,y)
{
   return x > y ? x : y;
}

inline void build(int x,int y)   //建树
{
	edge[++s].next=first[x];
	first[x]=s;
	edge[s].to=y;
}

inline void dfs1(int point,int fa) //第一遍dfs,算出size,father,depth,son
{
	size[point] = 1;
	father[point] = fa;
	depth[point] = depth[fa] + 1;
	for(int u=first[point];u;u=edge[u].next)
	{
	  int to = edge[u].to;
	  if(to == fa) continue;
	  dfs1(to,point);
	  size[point] += size[to];
	  if(size[to] > size[son[point]]) son[point] = to;
	}
}

inline void dfs2(int point,int fa) //第二遍dfs,算出rev,seg,top
{
	if(son[point])
	{
	  rev[son[point]] = ++tot;
	  seg[tot] = son[point];
	  top[son[point]] = top[point];
	  dfs2(son[point],point);
	}

	for(int u=first[point];u;u=edge[u].next)
	{
	  int to=edge[u].to;
	  if(!top[to])
	  {
	    rev[to] = ++tot;
	    seg[tot] = to;
	    top[to] = to;
	    dfs2(to,point);
	  }
	}
}

inline void update(int root)  //更新
{
	tree[root].maxx = mx(tree[root<<1].maxx , tree[root<<1|1].maxx);
	tree[root].sum = tree[root<<1].sum + tree[root<<1|1].sum;
}

inline void buildtree(int root,int l,int r)   //建线段树
{
	if(l==r)
	{
	  tree[root].maxx = tree[root].sum = num[seg[l]];
	  return;
	}
	int mid = l + r >> 1;
	buildtree(root<<1,l,mid);
	buildtree(root<<1|1,mid+1,r);
	update(root);
}

inline void change(int root,int l,int r,int pos,int num)   //操作I
{
   if(l==r)
   {
	  tree[root].maxx = tree[root].sum = num;
	  return;
   }
   int mid = l + r >> 1;
   if(pos <= mid) change(root<<1,l,mid,pos,num);
   else change(root<<1|1,mid+1,r,pos,num);
   update(root);
}

inline void Q(int root,int l,int r,int L,int R)  //操作II,III
{
   if(L<=l && R>=r)
   {
   	 MAX = mx(tree[root].maxx,MAX);
   	 SUM += tree[root].sum;
   	 return;
   }
   int mid = l + r >> 1;
   if(R<=mid) Q(root<<1,l,mid,L,R);
   else if(L >= mid+1) Q(root<<1|1,mid+1,r,L,R);
	else Q(root<<1,l,mid,L,R), Q(root<<1|1,mid+1,r,L,R);
}

inline void ask(int x,int y,int flag)   //询问
{
   SUM = 0,MAX = -1e9;
   int fax = top[x],fay = top[y];
   while(fax != fay)
   {
   	 if(depth[fax] < depth[fay]) swap(x,y),swap(fax,fay);
   	 Q(1,1,tot,rev[fax],rev[x]);
   	 x = father[fax];
   	 fax = top[x];
   }
   if(depth[x] > depth[y]) swap(x,y);
   Q(1,1,tot,rev[x],rev[y]);
   ans = !flag ? MAX : SUM;
}

inline void print(int x)   //输出优化
{
    if(x<0) {putchar('-'),x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

int main()
{
	n=get_int();
	for(int i=1;i<=n-1;i++)
	{
	  int x=get_int(),y=get_int();
	  build(x,y);
	  build(y,x);
    }
	for(int i=1;i<=n;i++) num[i]=get_int();

	tot = seg[1] = rev[1] = top[1] = 1;
	dfs1(1,0);
	dfs2(1,0);
	buildtree(1,1,tot);

	q=get_int();
	char ch[10];
	while(q--)
	{
	  scanf("%s",ch);
	  if(ch[1] == 'H')
	  {
	    int u=get_int(),t=get_int();
	    change(1,1,tot,rev[u],t);
	  }
	  if(ch[1] == 'M')
	  {
	  	int L=get_int(),R=get_int();
	  	ask(L,R,0);
	  	print(ans);
	  	putchar('\n');
	  }
	  if(ch[1] == 'S')
	  {
	  	int L=get_int(),R=get_int();
	  	ask(L,R,1);
	  	print(ans);
	  	putchar('\n');
	  }
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/81191692
今日推荐