bzoj 1036: [ZJOI2008]树的统计Count

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

HINT

Source

树的分治


以前觉得树链剖分很高端。。结果现在很轻松就可以写出来。

要学习树链剖分的看下面那个链接吧

http://blog.sina.com.cn/s/blog_7a1746820100wp67.html

【一开始用的cin读入string,结果一直在RE。后来改成scanf("%c",&x)一个个入读才过】

#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct line
{
     int s,t;
     int next;
}a[100001];
int edge;
int head[100001];
inline void add(int s,int t)
{
	 a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
}
struct tree
{
     int l,r;
     int s,max;
}tr[800001];
inline int max(int x,int y)
{
     if(x>y)
          return x;
     return y;
}
inline void up(int p)
{
     tr[p].max=max(tr[p*2].max,tr[p*2+1].max);
     tr[p].s=tr[p*2].s+tr[p*2+1].s;
}
inline void build(int p,int l,int r)
{
     tr[p].l=l;
     tr[p].r=r;
     tr[p].max=-21000000;
     if(l!=r)
     {
          int mid=(l+r)/2;
          build(p*2,l,mid);
          build(p*2+1,mid+1,r);
     }
}
inline void change(int p,int l,int r,int x)//单点修改 l==r 故未加tag操作 
{
     if(l<=tr[p].l&&tr[p].r<=r)
     {
          if(tr[p].max!=-21000000)
		       tr[p].max+=x;
		  else
		       tr[p].max=x;
          tr[p].s+=(tr[p].r-tr[p].l+1)*x;
     }
     else
     {
	      int mid=(tr[p].l+tr[p].r)/2;
		  if(l<=mid)
		       change(p*2,l,r,x);
		  if(r>mid)
		       change(p*2+1,l,r,x);
		  up(p);
     }
}
inline tree find(int p,int l,int r)
{
     if(l<=tr[p].l&&tr[p].r<=r)
          return tr[p];
     else
     {
	      int mid=(tr[p].l+tr[p].r)/2;
	      bool flag1=false,flag2=false;
	      tree x1,x2;
		  if(l<=mid)
		  {
		       x1=find(p*2,l,r);
		       flag1=true;
		  }
		  if(r>mid)
		  {
		       x2=find(p*2+1,l,r);
		       flag2=true;
		  }
		  tree x;
		  x.max=-21000000;
		  if(flag1)
		  {
		       if(flag2)
		       {
		            x.max=max(x1.max,x2.max);
		            x.s=x1.s+x2.s;
		       }
		       else
		            x=x1;
		  }
		  else
		       x=x2;
		  return x;
     }
}
int dep[100001],size[100001],son[100001],fa[100001];
int top[100001],w[100001];
int lson[100001]/*最大节点位置*/,mson[100001]/*最大节点值*/;
int tot;
inline void dfs1(int d)
{
     int i;
     for(i=head[d];i!=0;i=a[i].next)
     {
     	  int t=a[i].t;
          if(t!=fa[d])
          {
          	   dep[t]=dep[d]+1;
               fa[t]=d;
               dfs1(t);
               son[d]+=son[t]+1;
               if(son[t]>=mson[d])
               {
                    mson[d]=son[t];
                    lson[d]=t;
               }
          }
     }
}
inline void dfs2(int d)
{
     int i;
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(t==lson[d])
          {
               top[t]=top[d];
               tot++;
               w[t]=tot;
               dfs2(t);
          }
     }
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(t!=fa[d]&&t!=lson[d])
          {
               top[t]=t;
               tot++;
               w[t]=tot;
               dfs2(t);
          }
     }
}
tree xx;
inline tree ask(int s,int t)
{
	 int u=top[s],v=top[t];
	 tree x,xt;
	 x=xx;
	 x.max=-21000000;
     while(u!=v)
     {
          if(dep[u]>dep[v])
          {
          	   xt=find(1,w[u],w[s]);
          	   x.max=max(x.max,xt.max);
          	   x.s+=xt.s;
               s=fa[top[s]];
          }
          else
          {
          	   xt=find(1,w[v],w[t]);
          	   x.max=max(x.max,xt.max);
          	   x.s+=xt.s;
               t=fa[top[t]];
          }
          u=top[s];
          v=top[t];
     }
     if(w[s]<w[t])
          xt=find(1,w[s],w[t]);
     else
          xt=find(1,w[t],w[s]);
     x.max=max(x.max,xt.max);
     x.s+=xt.s;
     return x;
}
int val[100001];
int main()
{
//	 freopen("count.in","r",stdin);
//	 freopen("count.out","w",stdout);
     int n;
     scanf("%d",&n);
     int i,s,t;
     for(i=1;i<=n-1;i++)
     {
          scanf("%d%d",&s,&t);
          edge++;
          add(s,t);
          edge++;
          add(t,s);
     }
     dep[1]=1;
     dfs1(1);
     top[1]=1;
     tot++;
     w[1]=tot;
     dfs2(1);
     build(1,1,n);
     for(i=1;i<=n;i++)
     {
          scanf("%d",&val[i]);
          change(1,w[i],w[i],val[i]);
     }
     char x;
     int m;
     scanf("%d",&m);
     for(i=1;i<=m;i++)
     {
          scanf("%c",&x);
          while(x=='\n'||x=='\r')
               scanf("%c",&x);
          if(x=='Q')
          {
          	   int flag=1;
          	   scanf("%c",&x);
          	   if(x=='M')
          	        flag=1;
          	   else
          	        flag=2;
          	   while(x!=' ')
          	        scanf("%c",&x);
          	   scanf("%d%d",&s,&t);
          	   tree tx=ask(s,t);
          	   if(flag==1)
          	        printf("%d\n",tx.max);
          	   else if(flag==2)
          	        printf("%d\n",tx.s);
          }
          else if(x=='C')
          {
          	   while(x!=' ')
          	        scanf("%c",&x);
          	   scanf("%d%d",&s,&t);
               change(1,w[s],w[s],-val[s]);
               val[s]=t;
               change(1,w[s],w[s],val[s]);
          }
     }
     return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值