[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本身
输入输出格式
输入格式:
输入文件的第一行为一个整数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: 复制
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: 复制
4 1 2 2 10 6 5 6 5 16
说明
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
题解
考线段树的好吧
树剖预处理一下再加线段树的最大值查询加路径和查询就没了
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int N=2000001; struct node{ int to,next; }e[N] ; int head[N],num,ch[N],n,m; int lazy[N],sum[N],maxn[N]; int size[N],dep[N],son[N],fa[N],tot,l[N],a[N],top[N]; char ss[11]; void add(int from,int to) { num++; e[num].to=to; e[num].next=head[from]; head[from]=num; } void build(int root,int l,int r) { if(l==r) { //cout<<a[l]<<endl; maxn[root]=a[l]; sum[root]=a[l]; return ; } int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); sum[root]=sum[root<<1]+sum[root<<1|1]; maxn[root]=max(maxn[root<<1],maxn[root<<1|1]); return ; } void update(int root,int left,int right,int l,int r,int k) { if(l>right||r<left)return ; if(l<=left&&right<=r) { sum[root]=k; //lazy[root]=k; maxn[root]=k; return ; } int mid=(left+right)>>1; //if(lazy[root])push(root,left,right); if(mid>=l) update(root<<1,left,mid,l,r,k); if(mid<r) update(root<<1|1,mid+1,right,l,r,k); sum[root]=sum[root<<1]+sum[root<<1|1]; maxn[root]=max(maxn[root<<1],maxn[root<<1|1]); return ; } int query1(int root,int left,int right,int l,int r) { if(l>right||r<left)return 0; if(l<=left&&r>=right)return sum[root]; int mid=(left+right)>>1; int a=0,b=0; if(mid>=l) a=query1(root<<1,left,mid,l,r); if(mid<r) b=query1(root<<1|1,mid+1,right,l,r); return a+b; } int query2(int root,int left,int right,int l,int r) { int ans=-1e8; if(l>right||r<left)return -1e8; if(l<=left&&r>=right)return maxn[root]; int mid=(left+right)>>1; int a=-1e8,b=-1e8; if(mid>=l) a=query2(root<<1,left,mid,l,r); if(mid<r) b=query2(root<<1|1,mid+1,right,l,r); return ans=max(ans,max(a,b)); } void dfs1(int x) { size[x]=1; for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(!dep[v]) { dep[v]=dep[x]+1; fa[v]=x; dfs1(v); size[x]+=size[v]; if(size[v]>size[son[x]])son[x]=v; } } return ; } void dfs2(int x,int t) { l[x]=++tot;a[tot]=ch[x];top[x]=t; if(son[x])dfs2(son[x],t); for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(v!=fa[x]&&v!=son[x]) dfs2(v,v); } return ; } int cap(int x,int y,int f) { int maxx=0,fx=top[x],fy=top[y]; if(f==2)maxx=-1e8-9; while(fx!=fy) { if(dep[fx]<dep[fy]) { swap(x,y);swap(fx,fy); } if(f==1)maxx+=query1(1,1,n,l[fx],l[x]); else maxx=max(maxx,query2(1,1,n,l[fx],l[x])); x=fa[fx];fx=top[x]; } if(dep[x]>dep[y])swap(x,y); if(f==1)maxx+=query1(1,1,n,l[x],l[y]); else maxx=max(query2(1,1,n,l[x],l[y]),maxx); return maxx; } int read() { int x=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } int main() { memset(maxn,-127,sizeof(maxn)); n=read(); for(int i=1;i<n;i++) { int x,y;x=read();y=read(); add(x,y);add(y,x); } for(int i=1;i<=n;i++) { ch[i]=read(); } fa[1]=1; dep[1]=1; dfs1(1); dfs2(1,1); build(1,1,n); m=read();int x,y; for(int i=1;i<=m;i++) { scanf("%s",ss); if(ss[0]=='C') { x=read();y=read(); update(1,1,n,l[x],l[x],y); } else if(ss[1]=='M') { x=read();y=read(); printf("%d\n",cap(x,y,2)); } else { x=read();y=read(); printf("%d\n",cap(x,y,1)); } } return 0; }