首先就是7个树剖要用到的数组:
fa[i]:i的父亲
dep[i]:i的深度
size[i]:以i为根的子树的大小
son[i]:i的重儿子编号
top[i]:i所在链的顶端节点编号
dfn[i]:i的dfs序编号
rnk[i]:dfs序中第i个枚举节点的编号
显而易见,有rnk[dfn[i]]=i;
什么花花绿绿的功能咱先不说,先把这7个数组求出来。
方法是DFS*2;
DFS1:求fa,dep,size,son.
dep[1]=1;
dfs1(1);
void dfs1(int st)
{
son[st]=-1;
size[st]=1;
for(int i=head[st];i!=-1;i=e[i].ne)
{
if(dep[e[i].to]==0)
{
dep[e[i].to]=dep[st]+1;
fa[e[i].to]=st;
dfs1(e[i].to);
size[st]+=size[e[i].to];
if(son[st]==-1||size[e[i].to]>size[son[st]]) son[st]=e[i].to;
}
}
}
DFS2:求top,dfn,rnk.
cnt=0;
dfs2(1,1);
void dfs2(int st,int ft)
{
top[st]=ft;
cnt++;
dfn[st]=cnt;
rnk[cnt]=st;
if(son[st]==-1) return;
dfs2(son[st],ft);
for(int i=head[st];i!=-1;i=e[i].ne)
{
if(e[i].to==son[st]||e[i].to==fa[st]) continue;
dfs2(e[i].to,e[i].to);
}
}
So,we can learn another skill about it.
LCA!!!
Tarjan,倍增,朴素,动态树,RMQ…
都没用了。。。
预处理O(n),单次查询O(log2n)。
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])
{
u=fa[top[u]];
}
else
{
v=fa[top[v]];
}
}
if(dep[u]>dep[v])
{
return v;
}
else
{
return u;
}
}
最后就是最关键的一个技能了。
维护点与子树。
2256. 【ZJOI2008】树的统计 (Standard IO)
Time Limits: 2000 ms Memory Limits: 512000 KB Detailed Limits
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”的形式给出。
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
Sample Output
4
1
2
2
10
6
5
6
5
16
我哔哔哔,坚守树状数组的我完美WA,有时间再改,下次一定要用线段树!!!
#include<bits/stdc++.h>
using namespace std;
int n,m,i,j,tot,head[1111111],w[1111111],maxn,sum;
int dep[1111111],fa[1111111],siz[1111111],son[1111111],top[1111111],cnt,dfn[1111111],rnk[1111111],c[1111111],ssc[1111111],sscc[1111111];
char a[1111111];
struct eat{
int ne,to;
}e[1111111];
void add(int x,int y)
{
e[tot].to=y;
e[tot].ne=head[x];
head[x]=tot++;
}
int lb(int x)
{
return -x&x;
}
void ssszsz_add(int x,int y)
{
ssc[x]=y;
while(x<=n)
{
sscc[x]=y;
for(int j=1;j<lb(x);j<<=1)
{
if(sscc[x]<sscc[x-j])
{
sscc[x]=sscc[x-j];
}
}
x+=lb(x);
}
}
int ssszsz_qu(int x,int y)
{
int tot=0;
while(1)
{
if(tot<ssc[y]) tot=ssc[y];
if(x==y) break;
for(y-=1;y-x>=lb(y);y-=lb(y))
{
if(tot<sscc[y]) tot=sscc[y];
}
}
return tot;
}
void szsz_add(int x,int y)
{
while(x<=n)
{
c[x]+=y;
x+=lb(x);
}
}
int szsz_qu(int x)
{
int tot=0;
while(x>0)
{
tot+=c[x];
x-=lb(x);
}
return tot;
}
int szsz_sum(int x,int y)
{
return (szsz_qu(y)-szsz_qu(x-1));
}
int szsz_max(int x,int y)
{
return ssszsz_qu(x,y);
}
void dfs1(int st)
{
son[st]=-1;
siz[st]=1;
for(int i=head[st];i!=-1;i=e[i].ne)
{
if(dep[e[i].to]==0)
{
dep[e[i].to]=dep[st]+1;
fa[e[i].to]=st;
dfs1(e[i].to);
siz[st]+=siz[e[i].to];
if(son[st]==-1||siz[e[i].to]>siz[son[st]]) son[st]=e[i].to;
}
}
}
void dfs2(int st,int ft)
{
top[st]=ft;
cnt++;
dfn[st]=cnt;
rnk[cnt]=st;
if(son[st]==-1) return;
dfs2(son[st],ft);
for(int i=head[st];i!=-1;i=e[i].ne)
{
if(son[st]==e[i].to||e[i].to==fa[st]) continue;
dfs2(e[i].to,e[i].to);
}
}
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])
{
u=fa[top[u]];
}
else
{
v=fa[top[v]];
}
}
if(dep[u]>dep[v])
{
return v;
}
else
{
return u;
}
}
int pfmax(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
{
int t=u;
u=v;
v=t;
}
ans=max(ans,szsz_max(dfn[top[u]],dfn[u]));
u=fa[top[u]];
}
if(dep[u]>dep[v])
{
int t=u;
u=v;
v=t;
}
ans=max(ans,szsz_max(dfn[u],dfn[v]));
return ans;
}
int pfsum(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
{
int t=u;
u=v;
v=t;
}
ans+=szsz_sum(dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
if(dep[u]>dep[v])
{
int t=u;
u=v;
v=t;
}
ans+=szsz_sum(dfn[u],dfn[v]);
return ans;
}
int main()
{
memset(head,-1,sizeof head);
memset(e,-1,sizeof e);
scanf("%d",&n);
for(i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dep[1]=1;
dfs1(1);
dfs2(1,1);
for(i=1;i<=n;i++)
{
scanf("%d",&w[i]);
szsz_add(dfn[i],w[i]);
ssc[dfn[i]]=w[i];
sscc[dfn[i]]=w[i];
for(j=1;j<lb(dfn[i]);j<<=1)
{
if(sscc[dfn[i]]<sscc[dfn[i]-j])
{
sscc[dfn[i]]=sscc[dfn[i]-j];
}
}
}
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%s",a);
if(a[0]=='C')
{
int x,y;
scanf("%d%d",&x,&y);
szsz_add(dfn[x],y-w[x]);
ssszsz_add(dfn[x],y);
w[x]=y;
}
else
{
if(a[1]=='M')
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",pfmax(x,y));
}
else
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",pfsum(x,y));
}
}
}
}
改天用线段树再打一遍,不过我敢肯定树状数组除外的部分是对的。
哔哔哔。。。
为什么七十岁老人被恶毒夫妻推下悬崖却无人制止?为什么七个上身赤裸的男子殴打妇女却被人拍手叫好?为什么蛇蝎共处一窝却相安无事?这一切的背后,到底是道德的疏忽还是人格的泯灭亦或是社会的悲哀?如果你想了解这一切,请收看动画片《葫芦娃》!