题意:一棵树上每个节点有权值,定义三种操作:
Q a 询问a号节点的权值
I a b c a到b路径上所有节点权值加上c(包括a,b)
D a b c a到b路径上所有节点权值减去c(包括a,b)
对每个Q,输出结果
树链剖分:将树上的节点(或者边)通过特殊的dfs表上序号,序号作为下标套上线段树。
特殊的dfs : 将边分为重边跟轻边,dfs时优先走重边.
重边:一个节点的连接的子树节点最多的边为重边
修改操作:若当前询问点为a , b , fa,fb为a,b所在重链的最顶端且depth[fb]>depth[fa],则一次修改fb到b区间的数据,在使b=father[b] 直到 fa=fb
正确性:因为dfs 重链优先,则fb到b的上的节点的下标是连续的,修改则就跟线段树的修改一样 ,最坏情况执行log(n)次(a或b最多提升log(n)次到根节点)
接下来就是一般的线段树的操作了。
#include <iostream>
using namespace std;
#define M 100005
#include <string.h>
#include <string>
struct edges
{
int x,y,v,next;
}edge[M*2];
int head[M],num,z;
int tree[M*4],w[M],lazy[M*4];
int ted[M][3];
inline max(int a,int b)
{
return a>b?a:b;
}
void add_edge(int x,int y,int v)
{
edge[num].x=x;
edge[num].y=y;
edge[num].v=v;
edge[num].next=head[x];
head[x]=num++;
}
int top[M],fat[M],son[M],siz[M],dep[M];
int n,m,q;
int dfs(int f,int t)
{
fat[t]=f;
dep[t]=dep[f]+1;
siz[t]=1;
son[t]=0;
int i=head[t];
int mx=0,sum=0;
while(i)
{
if(edge[i].y!=f)
{
siz[t]+=dfs(t,edge[i].y);
if( siz[son[t]] < siz[edge[i].y] )
son[t]=edge[i].y;
}
i=edge[i].next;
}
return sum;
}
void dfs2(int r,int st)
{
top[r]=st;
w[r]=++z;
if( son[r] ) dfs2(son[r],st);
int i=head[r];
while(i)
{
int j=edge[i].y;
if( j!=son[r] && j!=fat[r] )
dfs2( j , j );
i=edge[i].next;
}
}
int nux[M];
void pushup(int root)
{
tree[root]=max(tree[root<<1],tree[root<<1+1]);
}
void pushdown(int root,int v)
{
if(lazy[root])
{
int l=root<<1,r=l+1,s=lazy[root];
lazy[root]=0;
lazy[l]+=s;
lazy[r]+=s;
tree[l]+=(v-v/2)*s;
tree[r]+=v/2*s;
}
}
void update2(int root,int low,int row,int l,int r,int v)
{
if(l<=low && r>=row )
{
lazy[root]+=v;
tree[root]+=v*(r-l+1);
return ;
}
if(row<l || low>r)
return ;
int ql=root*2,qr=ql+1,mid=(low+row)/2;
pushdown(root,row-low+1);
update2(ql,low,mid,l,r,v);
update2(qr,mid+1,row,l,r,v);
pushup(root);
}
void change(int l,int r,int v)
{
while(top[l]!=top[r])
{
if( dep[top[l]] > dep[top[r]] ) swap(l,r);
update2(1,1,z,w[top[r]],w[r],v);
r=top[r];
}
if(dep[l]>dep[r]) swap(l,r);
update2(1,1,z,w[l],w[r],v);
}
int mfind2(int root,int low,int hig,int loc)
{
if( low==hig )
return tree[root];
pushdown(root,hig-low+1);
int mid=(low+hig)/2,ret;
if(loc<=mid) ret=mfind2(root*2,low,mid,loc);
else ret=mfind2(root*2+1,mid+1,hig,loc);
pushup(root);
return ret;
}
/*---------------------------------------------------*/
void init2()
{
int i,k,x,y;
siz[0]=fat[0]=z=0,num=1;
memset(head,0,sizeof(head));
memset(top,0,sizeof(top));
memset(son,0,sizeof(son));
memset(tree,0,sizeof(tree));
memset(lazy,0,sizeof(lazy));
for(i=1;i<=n;i++)
cin>>nux[i];
for(i=1;i<=m;i++)
{
cin>>x>>y;
add_edge(x,y,0);
add_edge(y,x,0);
}
dfs(0,1);
dfs2(1,1);
for(i=1;i<=n;i++)
update2(1,1,z,w[i],w[i],nux[i]);
// for(i=1;i<=n;i++)
// cout<<son[i]<<' '<<top[i]<<' '<<fat[i]<<' '<<w[i]<<endl;
}
void work2()
{
string ques;
int a,b,c;
while(q--)
{
cin>>ques;
if(ques[0]=='Q')
{
cin>>a;
cout<<mfind2(1,1,z,w[a])<<endl;
}
else
{
cin>>a>>b>>c;
if(ques[0]=='D')
c=-c;
change(a,b,c);
}
}
}
int main()
{
while(cin>>n>>m>>q)
{
init2();
work2();
}
return 0;
}