AC日记——[ZJOI2008]树的统计Count bzoj 1036
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 15007 Solved: 6092
[Submit][Status][Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. 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
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
1
2
2
10
6
5
6
5
16
HINT
Source
思路:
裸线段树。
来,上代码:
#include <cstdio> #include <iostream> #include <algorithm> #define maxn 30001 using namespace std; struct TreeNodeType { int l,r,dis,mid,max_; }; struct TreeNodeType tree[maxn<<2]; struct EdgeType { int to,next; }; struct EdgeType edge[maxn<<1]; int if_z,n,m,dis[maxn],Enum,f[maxn],deep[maxn]; int size[maxn],tot,flag[maxn],belong[maxn],dis_[maxn]; int head[maxn],cnt; char Cget; inline void read_int(int &now) { if_z=1,now=0,Cget=getchar(); while(Cget>'9'||Cget<'0') { if(Cget=='-') if_z=-1; Cget=getchar(); } while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } now*=if_z; } inline void edge_add(int from,int to) { edge[++Enum].to=from,edge[Enum].next=head[to],head[to]=Enum; edge[++Enum].to=to,edge[Enum].next=head[from],head[from]=Enum; } void search(int now,int fa) { int pos=tot++; f[now]=fa,deep[now]=deep[fa]+1; for(int i=head[now];i;i=edge[i].next) { if(edge[i].to==fa) continue; search(edge[i].to,now); } size[now]=tot-pos; } void search_(int now,int chain) { flag[now]=++cnt,belong[now]=chain; dis_[flag[now]]=dis[now]; int pos=0; for(int i=head[now];i;i=edge[i].next) { if(flag[edge[i].to]) continue; if(size[edge[i].to]>size[pos]) pos=edge[i].to; } if(pos!=0) search_(pos,chain); else return ; for(int i=head[now];i;i=edge[i].next) { if(flag[edge[i].to]) continue; search_(edge[i].to,edge[i].to); } } int max(int SOME1,int SOME2) { if(SOME1>SOME2) return SOME1; else return SOME2; } inline void tree_up(int now) { tree[now].dis=tree[now<<1].dis+tree[now<<1|1].dis; tree[now].max_=max(tree[now<<1].max_,tree[now<<1|1].max_); } void tree_build(int now,int l,int r) { tree[now].l=l,tree[now].r=r; if(l==r) { tree[now].dis=dis_[++cnt]; tree[now].max_=dis_[cnt]; return ; } tree[now].mid=(l+r)>>1; tree_build(now<<1,l,tree[now].mid); tree_build(now<<1|1,tree[now].mid+1,r); tree_up(now); } void tree_change(int now,int to,int x) { if(tree[now].l==tree[now].r&&tree[now].l==to) { tree[now].dis=x,tree[now].max_=x; return ; } if(to>tree[now].mid) tree_change(now<<1|1,to,x); else tree_change(now<<1,to,x); tree_up(now); } int tree_query_max(int now,int l,int r) { if(tree[now].l==l&&tree[now].r==r) { return tree[now].max_; } if(l>tree[now].mid) return tree_query_max(now<<1|1,l,r); else if(r<=tree[now].mid) return tree_query_max(now<<1,l,r); else return max(tree_query_max(now<<1,l,tree[now].mid),tree_query_max(now<<1|1,tree[now].mid+1,r)); } int tree_query_dis(int now,int l,int r) { if(tree[now].l==l&&tree[now].r==r) { return tree[now].dis; } if(l>tree[now].mid) return tree_query_dis(now<<1|1,l,r); else if(r<=tree[now].mid) return tree_query_dis(now<<1,l,r); else return tree_query_dis(now<<1,l,tree[now].mid)+tree_query_dis(now<<1|1,tree[now].mid+1,r); } inline int solve_dis(int x,int y) { int ans=0; while(belong[x]!=belong[y]) { if(deep[belong[x]]<deep[belong[y]]) swap(x,y); ans+=tree_query_dis(1,flag[belong[x]],flag[x]); x=f[belong[x]]; } ans+=tree_query_dis(1,min(flag[x],flag[y]),max(flag[x],flag[y])); return ans; } inline int solve_max(int x,int y) { int ans=-0x7ffffff; while(belong[x]!=belong[y]) { if(deep[belong[x]]<deep[belong[y]]) swap(x,y); ans=max(ans,tree_query_max(1,flag[belong[x]],flag[x])); x=f[belong[x]]; } ans=max(ans,tree_query_max(1,min(flag[x],flag[y]),max(flag[x],flag[y]))); return ans; } int main() { read_int(n); int from,to; for(int i=1;i<n;i++) { read_int(from),read_int(to); edge_add(from,to); } for(int i=1;i<=n;i++) read_int(dis[i]); search(1,0),search_(1,1),cnt=0,tree_build(1,1,n); read_int(m); char ch[10]; for(int i=1;i<=m;i++) { scanf("%s",ch);read_int(from),read_int(to); if(ch[0]=='C') { tree_change(1,flag[from],to); } else { if(ch[1]=='S') printf("%d\n",solve_dis(from,to)); else printf("%d\n",solve_max(from,to)); } } return 0; }