bzoj1036 [ZJOI2008]树的统计

一棵树上有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”的操作,每行输出一个整数表示要求输出的结果。

树剖模板。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cmath>
  5 #include<cstring>
  6 using namespace std;
  7 
  8 const int INF=1e9+7,NN=30007,MM=1e5+7;
  9 
 10 int n,m,sz;
 11 int a[NN],deep[NN],size[NN],fa[NN],pos[NN],bl[NN];
 12 int cnt,head[NN],next[MM],rea[MM];
 13 struct Node
 14 {
 15     int l,r,mx,sum;
 16 }tree[MM];
 17 
 18 void add(int u,int v)
 19 {
 20     cnt++;
 21     next[cnt]=head[u];
 22     head[u]=cnt;
 23     rea[cnt]=v;
 24 }
 25 void dfs_init(int x)
 26 {
 27     size[x]=1;
 28     for (int i=head[x];i!=-1;i=next[i])
 29     {
 30         int v=rea[i];
 31         if (v==fa[x]) continue;
 32         deep[v]=deep[x]+1;
 33         fa[v]=x;
 34         dfs_init(v);
 35         size[x]+=size[v];
 36     }
 37 }
 38 void dfs_make(int x,int chain)//chain表示重链首的编号 
 39 {
 40     int k=0;//找重链 
 41     sz++;
 42     pos[x]=sz;//分配编号;
 43     bl[x]=chain;
 44     for (int i=head[x];i!=-1;i=next[i])
 45     {
 46         int v=rea[i];
 47         if (deep[v]>deep[x]&&size[v]>size[k]) k=v;
 48     }
 49     if (k==0) return;
 50     dfs_make(k,chain);
 51     for (int i=head[x];i!=-1;i=next[i])
 52     {
 53         int v=rea[i];
 54         if (deep[v]>deep[x]&&k!=v) dfs_make(v,v);
 55     }
 56 }
 57 void build(int k,int l,int r)
 58 {
 59     tree[k].l=l,tree[k].r=r;
 60     if (l==r) return;
 61     int mid=(l+r)>>1;
 62     build(k<<1,l,mid),build((k<<1)+1,mid+1,r); 
 63 }
 64 void change(int k,int x,int y)
 65 {
 66     int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
 67     if (l==r){tree[k].sum=tree[k].mx=y;return;}
 68     if (x<=mid) change(k<<1,x,y);
 69     else change(k<<1|1,x,y);
 70     tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
 71     tree[k].mx=max(tree[k<<1].mx,tree[k<<1|1].mx);
 72 }
 73 int query_sum(int k,int x,int y)
 74 {
 75     int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
 76     if (l==x&&r==y) return tree[k].sum;
 77     if (y<=mid) return query_sum(k<<1,x,y);
 78     else if (x>mid) return query_sum(k<<1|1,x,y);
 79     else return query_sum(k<<1,x,mid)+query_sum(k<<1|1,mid+1,y);
 80 }
 81 int query_max(int k,int x,int y)
 82 {
 83     int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1;
 84     if (l==x&&y==r) return tree[k].mx;
 85     if (y<=mid) return query_max(k<<1,x,y);
 86     else if (x>mid) return query_max(k<<1|1,x,y);
 87     else return max(query_max(k<<1,x,mid),query_max(k<<1|1,mid+1,y));
 88 }
 89 int solve_sum(int x,int y)
 90 {
 91     int sum=0;
 92     while (bl[x]!=bl[y])//表示标记不同
 93     {
 94         if (deep[bl[x]]<deep[bl[y]]) swap(x,y);
 95         sum+=query_sum(1,pos[bl[x]],pos[x]);
 96         x=fa[bl[x]]; //跳完整条重链。 
 97     }
 98     if (pos[x]>pos[y]) swap(x,y);
 99     sum+=query_sum(1,pos[x],pos[y]);
100     return sum;
101 }
102 int solve_max(int x,int y)
103 {
104     int mx=-INF;
105     while (bl[x]!=bl[y])
106     {
107         if (deep[bl[x]]<deep[bl[y]]) swap(x,y);
108         mx=max(mx,query_max(1,pos[bl[x]],pos[x]));
109         x=fa[bl[x]];
110     }
111     if (pos[x]>pos[y]) swap(x,y);
112     mx=max(mx,query_max(1,pos[x],pos[y]));
113     return mx;
114 }
115 int main()
116 {
117     memset(head,-1,sizeof(head));
118     scanf("%d",&n);
119     for (int i=1;i<n;i++)
120     {
121         int x,y;
122         scanf("%d%d",&x,&y);
123         add(x,y),add(y,x);
124     }
125     for (int i=1;i<=n;i++)
126         scanf("%d",&a[i]);
127     dfs_init(1);
128     dfs_make(1,1);    
129     build(1,1,n);//建树。
130     for (int i=1;i<=n;i++)
131         change(1,pos[i],a[i]);
132     scanf("%d",&m);
133     char c[10];
134     for (int i=1;i<=m;i++)
135     {
136         int x,y;
137         scanf("%s%d%d",c,&x,&y);
138         if (c[0]=='C')
139         {
140             a[x]=y;
141             change(1,pos[x],y);
142         }
143         else
144         {
145             if (c[1]=='M') printf("%d\n",solve_max(x,y));
146             else printf("%d\n",solve_sum(x,y));
147         }
148     }
149 }

 

posted @ 2017-09-10 09:45  Kaiser-  阅读(174)  评论(0编辑  收藏  举报