题目链接
思路:对于每次询问,主要是看x和root的关系,求出root和xlca
root=x ,ans为总的和
lca=x 那么ans=总的和-(root到x这条链上父节点为x的那个点的子树和)
否则,ans就是x的子树和
求子树和和修改直接线段树维护。节点的编号和lca我是用的树链剖分求的
AC代码:
#include
using namespace std;
const int maxn=1e4+10;
int val[maxn];
struct E
{
int next,to;
}edge[maxn*2];
int head[maxn],deep[maxn],top[maxn],fa[maxn],son[maxn],sz[maxn],id[maxn],fid[maxn],tot,num;
void add_edge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs1(int u,int f,int dep)
{
fa[u]=f;
son[u]=0;
sz[u]=1;
deep[u]=dep;
for(int i=head[u];i!=-1;i=edge[i].next){
int ff=edge[i].to;
if(ff==f) continue;
dfs1(ff,u,dep+1);
sz[u]+=sz[ff];
if(sz[ff]>sz[son[u]]) son[u]=ff;
}
}
void dfs2(int u,int tp)
{
id[u]=++num;
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];i!=-1;i=edge[i].next){
int ff=edge[i].to;
if(ff==fa[u]||ff==son[u]) continue;
dfs2(ff,ff);
}
}
void init()
{
num=tot=0;
memset(head,-1,sizeof(head));
}
#define ll t[rt].l
#define rr t[rt].r
#define ls rt<<1
#define rs rt<<1|1
struct node
{
int l,r;
int val;
}t[maxn<<2];
void pushup(int rt)
{
t[rt].val=t[ls].val+t[rs].val;
}
void build(int rt,int l,int r)
{
t[rt].l=l;
t[rt].r=r;
if(l==r){
t[rt].val=val[l];
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
void update(int rt,int pos,int v)
{
if(ll==rr){
t[rt].val=v;
return;
}
int mid=(ll+rr)>>1;
if(pos<=mid) update(ls,pos,v);
else update(rs,pos,v);
pushup(rt);
}
int query(int rt,int l,int r)
{
if(l<=ll&&rr<=r) return t[rt].val;
int ans=0;
int mid=(ll+rr)>>1;
if(l<=mid) ans+=query(ls,l,r);
if(r>mid) ans+=query(rs,l,r);
return ans;
}
int Lca(int u,int v)
{
while(top[u]!=top[v]){
if(deep[top[u]]deep[v]) swap(u,v);
if(u==v) return id[u]+1;
return id[v]-(deep[v]-deep[u])+1;
}
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--){
init();
int n;
scanf("%d",&n);
int u,v;
for(int i=1;i