(ZJOI2008)BZOJ1036 树的统计

题意:维护树上一条路径上的结点权值最大值或和

正解:树链剖分+线段树

没什么好说的,链剖裸题。先树链剖分再根据访问次序建立线段树,用线段树动态维护。

模板题练手。

  1 //It is made by jump~
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <algorithm>
  8 using namespace std;
  9 typedef long long LL;
 10 const int MAXN = 30011;
 11 const int inf = (1<<30);
 12 int n;
 13 int total,ecnt;
 14 int U,VV;
 15 int a[MAXN];
 16 int id[MAXN],pre[MAXN];
 17 int top[MAXN],siz[MAXN],zhongerzi[MAXN],father[MAXN],deep[MAXN];
 18 int next[MAXN*2],to[MAXN*2],first[MAXN];
 19 char ch[8];
 20
 21 struct node{
 22     int l,r;
 23     int _max;int _sum;
 24 }jump[MAXN*4];
 25
 26 void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
 27
 28 int getint()
 29 {
 30        int w=0,q=0;
 31        char c=getchar();
 32        while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar();
 33        if (c==‘-‘)  q=1, c=getchar();
 34        while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar();
 35        return q ? -w : w;
 36 }
 37
 38 void build(int root,int l,int r){
 39     jump[root].l=l;jump[root].r=r;
 40     if(jump[root].l==jump[root].r) {
 41         jump[root]._sum=jump[root]._max=a[ pre[l] ];
 42         return ;
 43     }
 44     int lc=root*2,rc=root*2+1;
 45     int mid=l+(r-l)/2;
 46     build(lc,l,mid); build(rc,mid+1,r);
 47     jump[root]._sum=jump[lc]._sum+jump[rc]._sum;
 48     jump[root]._max=max(jump[lc]._max,jump[rc]._max);
 49 }
 50
 51 void dfs1(int u,int fa){
 52     siz[u]=1;
 53     for(int i=first[u];i;i=next[i]) {
 54         int v=to[i];
 55         if(v!=fa) {
 56             father[v]=u;
 57             deep[v]=deep[u]+1;
 58             dfs1(v,u);
 59             siz[u]+=siz[v];
 60             if(siz[v]>siz[ zhongerzi[u] ]) zhongerzi[u]=v;
 61         }
 62     }
 63 }
 64
 65 void dfs2(int u,int fa){
 66     id[u]=++total; pre[total]=u;
 67     if(zhongerzi[u]) top[zhongerzi[u]]=top[u],dfs2(zhongerzi[u],u);
 68     for(int i=first[u];i;i=next[i]) {
 69         int v=to[i];
 70         if(v==fa || v==zhongerzi[u]) continue;
 71         top[v]=v;
 72         dfs2(v,u);
 73     }
 74 }
 75
 76 int query_sum(int root,int x,int y){
 77     if(jump[root].l>=x && jump[root].r<=y) return jump[root]._sum;
 78     int da=0;
 79     int mid=jump[root].l+(jump[root].r-jump[root].l)/2;
 80     int lc=root*2,rc=root*2+1;
 81     if(x<=mid) da+=query_sum(lc,x,y);
 82     if(y>mid) da+=query_sum(rc,x,y);
 83     return da;
 84 }
 85
 86
 87 int query_max(int root,int x,int y){
 88     if(jump[root].l>=x && jump[root].r<=y) return jump[root]._max;
 89     int da=-inf;
 90     int mid=jump[root].l+(jump[root].r-jump[root].l)/2;
 91     int lc=root*2,rc=root*2+1;
 92     if(x<=mid) da=max(da,query_max(lc,x,y));
 93     if(y>mid) da=max(da,query_max(rc,x,y));
 94     return da;
 95 }
 96
 97 int find_max(int x,int y){
 98     int f1=top[x],f2=top[y];
 99     int daan=-inf;
100     while(f1!=f2){
101             if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y);
102             daan=max(daan,query_max(1,id[f1],id[x]));
103             x=father[f1];
104             f1=top[x];
105     }
106     if(deep[x]<deep[y]) swap(x,y);
107     daan=max(daan,query_max(1,id[y],id[x]));
108     return daan;
109 }
110
111 int find_sum(int x,int y){
112     int f1=top[x],f2=top[y];
113     int daan=0;
114     while(f1!=f2){
115           if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y);
116           daan+=query_sum(1,id[f1],id[x]);
117           x=father[f1]; f1=top[x];
118     }
119     if(deep[x]<deep[y]) swap(x,y);
120     daan+=query_sum(1,id[y],id[x]);
121     return daan;
122 }
123
124 void update(int root,int o,int add){
125     if(jump[root].l==jump[root].r){
126         jump[root]._sum+=add;
127         jump[root]._max+=add;return ;
128     }
129     int lc=root*2,rc=root*2+1;
130     int mid=jump[root].l+(jump[root].r-jump[root].l)/2;
131     if(o<=mid) update(lc,o,add); else update(rc,o,add);
132     jump[root]._sum=jump[lc]._sum+jump[rc]._sum;
133     jump[root]._max=max(jump[lc]._max,jump[rc]._max);
134 }
135
136 int main()
137 {
138   n=getint();
139   int x,y;
140   for(int i=1;i<n;i++){
141       x=getint();y=getint();
142       next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y;
143       next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x;
144    }
145
146   deep[1]=1;  dfs1(1,0);
147   top[1]=1;  dfs2(1,0);
148
149   for(int i=1;i<=n;i++) a[i]=getint();
150   build(1,1,n);
151   int Q=getint();
152
153   for(int i=1;i<=Q;i++){
154       scanf("%s",ch);
155       if(ch[1]==‘M‘){
156           printf("%d\n",find_max(x,y));
157       }
158       else if(ch[1]==‘S‘){
159           x=getint();y=getint();
160           printf("%d\n",find_sum(x,y));
161       }
162       else{
163           U=getint();VV=getint();
164           update(1,id[U],VV-a[U]);a[U]=VV;
165       }
166    }
167   return 0;
168 }
时间: 2024-10-25 06:40:08

(ZJOI2008)BZOJ1036 树的统计的相关文章

[ZJOI2008][BZOJ1036] 树的统计count

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 7980  Solved: 3266[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 II

bzoj1036 树的统计(树链剖分+线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 15120  Solved: 6141[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

【BZOJ1036】【ZJOI2008】树的统计Count 树链剖分裸题

题解:裸的,没什么好说的. 树链剖分不会的先理解一下重链轻链,然后直接扒我代码理解就行了. 贴代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 30100 #define inf 0x3f3f3f3f using namespace std; struct KSD { int u,v,next; }e[N<<1];

树剖裸题——BZOJ1036 树的统计

1 #include<cstring> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstdio> 5 #define foru(i,x,y) for(int i=x;i<=y;i++) 6 #define clr(a) memset(a,0,sizeof(a)) 7 using namespace std; 8 const int N=100010; 9 struct edge{int to,

BZOJ1036 树的统计Count(同时求sum max)

#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; const int N=30010; s

【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之间有

BZOJ1036 树的统计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之间

[bzoj1036]树的统计

链剖好难调啊~调了半个小时,终于发现线段树写挂了233 唉,我真是个假人~ 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,表示节点

[JSOI2008][BZOJ1036] 树的统计 - 树链剖分

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 & Output Input 输入文件的第一行为一个整数n,表示节点的个数. 接下来n – 1行,每行2个整