您的位置:首页 > 大数据 > 人工智能

HDU5405 Sometimes Naive

2016-07-10 13:57 363 查看
传送门

题目大意

给定一棵n个节点的带点权树,m次操作,为修改单点点权或者给出u,v,询问∑ni=1∑nj=1f(i,j).其中若path(i,j)与path(u,v)有交集,则f(i,j)=vali⋅valj,否则f(i,j)=0,结果对109+7取模.

1≤n,m≤105,0≤vali≤109.

题解

直接计算好像无从下手,然而倒着考虑思路一下子就会打开了.

即计算所有点对的权值乘积之和,再减去路径与path(u,v)有交集的点对的权值乘积之和.

于是问题转化为求所有点权和的平方减去去掉path(u,v)后形成的若干子树的点权和的平方的和.

首先我们可以用dfs序+bit维护子树的权值和.

如果参考HDU5293 Tree Chain Problem的做法,我们可以O(lg2n)进行询问,但是修改操作似乎无法高效完成.

这时候还有一种机智的做法.

令wi表示以i为根的子树的val之和,然后我们树剖用bit维护每个节点的轻儿子的w值的平方和.

这样子询问进行跳重链时就可以快速把去掉这条链形成的子树的信息收集上来了.

当然还需要单点询问什么的,避免遗漏和重复计算.

最后还要算上lca(u,v)上面那棵子树的值.

还有修改操作,依旧是跳重链一直跳到根上,每次跳跃时单点修改一下跳到的那个点的信息即可.

然后发现那道Tree Chain Problem似乎也可以这样维护轻儿子的信息来做?

总复杂度O(nlg2n).

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fi first
#define se second
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=(int)1e5+5,mod=(int)1e9+7;
int n,val
,tot_sum,
tot_edge,head
,
dfs_clock,pre
,post
,
par
,dep
,sz
,
allc,heavy_son
,top
,Tid
,
val_bit
,w_bit
;
pii edge[N<<1];
void rd(int &res){
res=0;
char c;
while(c=getchar(),c<48);
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>47);
}
inline void add_edge(int u,int v){
edge[tot_edge]=pii(v,head[u]);
head[u]=tot_edge++;
}
inline void mod_add(int &a,int b){
if((a+=b)>=mod)a-=mod;
}
inline int sqr(int x){
return 1ll*x*x%mod;
}
void add(int *bit,int x,int v){
for(;x<=n;x+=lowbit(x))
mod_add(bit[x],v);
}
int sum(int *bit,int x){
int res=0;
for(;x;x-=lowbit(x))
mod_add(res,bit[x]);
return res;
}
int query_sum(int *bit,int L,int R){
return sum(bit,R)-sum(bit,L-1);
}
int query_subtree_sum(int v){
return query_sum(val_bit,pre[v],post[v]);
}
void dfs(int cur,int fa=0,int depth=0){
add(val_bit,pre[cur]=++dfs_clock,val[cur]);
par[cur]=fa;
dep[cur]=depth++;
sz[cur]=1;
heavy_son[cur]=0;
for(int i=head[cur];~i;i=edge[i].se){
int son=edge[i].fi;
if(son==fa)continue;
dfs(son,cur,depth);
sz[cur]+=sz[son];
if(!heavy_son[cur]||sz[son]>sz[heavy_son[cur]])
heavy_son[cur]=son;
}
post[cur]=dfs_clock;
}
void allc_dfs(int cur,int anc){
top[cur]=anc;
Tid[cur]=++allc;
if(heavy_son[cur])allc_dfs(heavy_son[cur],anc);
int light_sum=0;
for(int i=head[cur];~i;i=edge[i].se){
int son=edge[i].fi;
if(son==par[cur]||son==heavy_son[cur])continue;
allc_dfs(son,son);
mod_add(light_sum,sqr(query_subtree_sum(son)));
}
add(w_bit,Tid[cur],light_sum);
}
void Modify(int tar,int v){
int delta=v-val[tar];
if(delta<0)delta+=mod;
val[tar]=v;
mod_add(tot_sum,delta);
add(val_bit,pre[tar],delta);

for(tar=top[tar];par[tar];tar=top[par[tar]]){
int cur_sum=query_subtree_sum(tar),
tmp=sqr(cur_sum)-sqr(cur_sum-delta);
if(tmp<0)tmp+=mod;
add(w_bit,Tid[par[tar]],tmp);
}
}
int Query(int u,int v){
ll ans=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);

ans+=query_sum(w_bit,Tid[top[u]],Tid[u]);
if(heavy_son[u])ans+=sqr(query_subtree_sum(heavy_son[u]));
ans-=sqr(query_subtree_sum(top[u]));

u=par[top[u]];
}

if(dep[u]>dep[v])swap(u,v);

ans+=query_sum(w_bit,Tid[u],Tid[v]);
if(heavy_son[v])ans+=sqr(query_subtree_sum(heavy_son[v]));

ans+=sqr(tot_sum-query_subtree_sum(u));

ans=sqr(tot_sum)-ans;
ans%=mod;
if(ans<0)ans+=mod;
return (int)ans;
}
void solve(){
int m,ope,a,b;
rd(m);
tot_sum=0;
for(int i=1;i<=n;++i){
rd(val[i]);
mod_add(tot_sum,val[i]);
}
tot_edge=0;
memset(head,-1,n+1<<2);
for(int i=1,u,v;i<n;++i){
rd(u);rd(v);
add_edge(u,v);
add_edge(v,u);
}
dfs_clock=0;
memset(val_bit,0,n+1<<2);
memset(w_bit,0,n+1<<2);
dfs(1);
allc=0;
allc_dfs(1,1);
while(m--){
rd(ope);rd(a);rd(b);
if(ope==1)Modify(a,b);
else printf("%d\n",Query(a,b));
}
}
int main(){
while(~scanf("%d",&n))solve();
return 0;
}
/*

Jul.10.16

Tags:tree,dfs clock,bit,HLD
Submissions:1

Memory(KB) 13560
Time(ms) 1201
Length(Bytes) 3088

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU dfs序 bit 树链剖分