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之间有一条边相连。接下来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
题解:树链剖分模板题。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,q,sz,cnt,m;
struct use{
int st,en;
}b[100001];
struct zff{
int maxx,sum;
}tree[1000001];
int fa[100001][15],size[1000001],deep[100001],point[100001],next[1000001],vis[1000001],pos[1000001],w[1000001],aa,bb;
int belong[1000001],ffpos[1000001];
char ch[10001];
void add(int x,int y)
{
next[++cnt]=point[x];point[x]=cnt;
b[cnt].st=x;b[cnt].en=y;
}
void init()
{
int a,b;
scanf("%d",&n);
for (int i=1;i<=n-1;i++)
{
scanf("%d%d",&a,&b);
add(a,b);add(b,a);
}
for (int i=1;i<=n;i++)
scanf("%d",&w[i]);
}
void build(int x,int l,int r)
{
int mid;
if (l==r){tree[x].maxx=w[ffpos[l]];tree[x].sum=w[ffpos[l]];return;}
mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
tree[x].maxx=max(tree[x*2].maxx,tree[x*2+1].maxx);
tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
}
void dfs(int x)
{
size[x]=1;vis[x]=1;
for (int i=1;i<=14;i++)
{
if (deep[x]<(1<<i)) break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for (int i=point[x];i;i=next[i])
{
if (vis[b[i].en]==1) continue;
deep[b[i].en]=deep[x]+1;
fa[b[i].en][0]=x;
dfs(b[i].en);
size[x]+=size[b[i].en];
}
}
void dfs2(int x,int c)
{
int k(0);
pos[x]=++sz;
ffpos[sz]=x;
belong[x]=c;
for (int i=point[x];i;i=next[i]) if (size[b[i].en]>size[k]&&deep[b[i].en]>deep[x]) k=b[i].en;
if (k==0) return;
dfs2(k,c);
for (int i=point[x];i;i=next[i]) if (deep[b[i].en]>deep[x]&&b[i].en!=k) dfs2(b[i].en,b[i].en);
}
int lca(int x,int y)
{
int t;
if(deep[x]<deep[y]) swap(x,y);t=deep[x]-deep[y];
for (int i=0;i<=14;i++) if (t&(1<<i)) x=fa[x][i];
for (int i=14;i>=0;i--)
if (fa[x][i]!=fa[y][i]) {x=fa[x][i];y=fa[y][i];}
if (x==y) return x;else return fa[x][0];
}
void insert(int k,int l,int r)
{
int mid;
if(l==r&&l==pos[aa]){tree[k].maxx=w[aa];tree[k].sum=w[aa];return;}
mid=(l+r)/2;
if (pos[aa]<=mid) insert(k*2,l,mid);
else insert(k*2+1,mid+1,r);
tree[k].maxx=max(tree[2*k].maxx,tree[2*k+1].maxx);
tree[k].sum=tree[2*k].sum+tree[2*k+1].sum;
}
int qsum(int k,int l,int r,int xx,int yy)
{
int mid,zsum=0;
if (xx<=l&&r<=yy) return tree[k].sum;
mid=(l+r)/2;
if (xx<=mid) zsum+=qsum(k*2,l,mid,xx,yy);
if (yy>mid) zsum+=qsum(k*2+1,mid+1,r,xx,yy);
return zsum;
}
int qmax(int k,int l,int r,int xx,int yy)
{
int mid,zmax=-999999999;
if (xx<=l&&r<=yy)
{
return tree[k].maxx;
}
mid=(l+r)/2;
if (xx<=mid) zmax=max(zmax,qmax(k*2,l,mid,xx,yy));
if (yy>mid) zmax=max(zmax,qmax(k*2+1,mid+1,r,xx,yy));
return zmax;
}
int ssum(int x,int y)
{
int zsum(0);
while (belong[x]!=belong[y])
{
zsum+=qsum(1,1,n,pos[belong[x]],pos[x]);
x=fa[belong[x]][0];
}
zsum+=qsum(1,1,n,pos[y],pos[x]);
return zsum;
}
int smax(int x,int y)
{
int zmax(-999999999);
while (belong[x]!=belong[y])
{
zmax=max(zmax,qmax(1,1,n,pos[belong[x]],pos[x]));
x=fa[belong[x]][0];
}
zmax=max(zmax,qmax(1,1,n,pos[y],pos[x]));
return zmax;
}
void solve()
{
int t;
build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s%d%d",ch,&aa,&bb);
if (ch[0]=='C'){w[aa]=bb;insert(1,1,n);}
else
{
t=lca(aa,bb);
if (ch[1]=='M') printf("%d\n",max(smax(aa,t),smax(bb,t)));
else printf("%d\n",ssum(aa,t)+ssum(bb,t)-w[t]);
}
}
}
int main()
{
init();
dfs(1);
dfs2(1,1);
solve();
}