树链剖分-bzoj1036
一棵树上有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
http://www.hekai.site/wordpress/2017/06/24/%E8%AF%A6%E8%A7%A3%E6%A0%91%E9%93%BE%E5%89%96%E5%88%86/
HK大佬的blog,一看就懂
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define N 30500 using namespace std; int n,tot,lable,next[N<<1],head[N<<1],to[N<<1],a[N],fa[N],dep[N],son[N],size[N],tid[N],number[N]; int top[N],Max[N*4],sum[N*4]; bool visit[N]; void make_way(int u,int v) { to[++tot]=v; next[tot]=head[u]; head[u]=tot; } void dfs(int u,int depth,int father) { visit[u]=1;fa[u]=father,dep[u]=depth,son[u]=0,size[u]=1; int maxsize=0; for(int edge=head[u];edge;edge=next[edge]) { int v=to[edge]; if(!visit[v]) { dfs(v,depth+1,u); size[u]+=size[v]; if(size[v]>maxsize) { son[u]=v;maxsize=size[v]; } } } } void dfs1(int u,int ancestor) { visit[u]=1,tid[u]=++lable,number[lable]=u,top[u]=ancestor; if(son[u]!=0) dfs1(son[u],ancestor); for(int edge=head[u];edge;edge=next[edge]) if(!visit[to[edge]])dfs1(to[edge],to[edge]); } void update(int u) { Max[u]=max(Max[u<<1],Max[u<<1|1]); sum[u]=sum[u<<1]+sum[u<<1|1]; } void build(int u,int l,int r) { Max[u]=-1<<29,sum[u]=0; if(l==r) { Max[u]=sum[u]=a[number[l]]; return; } int mid=(l+r)>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); update(u); } void change(int u,int l,int r,int x,int val) { if(l==r) { Max[u]=sum[u]=val; return; } int mid=(l+r)>>1; if(x<=mid) change(u<<1,l,mid,x,val);else change(u<<1|1,mid+1,r,x,val); update(u); } int query(int u,int l,int r,int x,int y,int q) { //cout<<u<<' '<<l<<' '<<r<<' '<<x<<' '<<y<<' '<<q<<endl; //if(!u) return 0; if (x==l&&r==y) { if (q==0) return Max[u];else return sum[u]; } int mid=(l+r)>>1; if(x>mid) return query(u<<1|1,mid+1,r,x,y,q);else if(y<=mid) return query(u<<1,l,mid,x,y,q);else { if(q==0) return max(query(u<<1,l,mid,x,mid,q),query(u<<1|1,mid+1,r,mid+1,y,q));else return query(u<<1,l,mid,x,mid,q)+query(u<<1|1,mid+1,r,mid+1,y,q); } } int Query(int x,int y,int q) { int ans; if(q) ans=0;else ans=-1<<29; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); if(q==0) ans=max(ans,query(1,1,n,tid[top[x]],tid[x],0)); else ans+=query(1,1,n,tid[top[x]],tid[x],1); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); if(q==0) ans=max(ans,query(1,1,n,tid[x],tid[y],0));else ans+=query(1,1,n,tid[x],tid[y],1); return ans; } int main() { scanf("%d",&n); for(int i=1;i<n;i++) { int x,y; scanf("%d %d",&x,&y); make_way(x,y); make_way(y,x); } for(int i=1;i<=n;i++) scanf("%d",&a[i]); int m; scanf("%d",&m); memset(visit,0,sizeof(visit)); dfs(1,1,0); memset(visit,0,sizeof(visit)); dfs1(1,0); //cout<<n<<endl; build(1,1,n); char str[10]; for(int i=1;i<=m;i++) { int x,y; scanf("%s %d %d",str,&x,&y); if(str[0]=='C') change(1,1,n,tid[x],y);else if(str[1]=='M') printf("%d\n",Query(x,y,0));else printf("%d\n",Query(x,y,1)); } return 0; }
不过HK的线段树太玄妙,看不懂