一种明显的做法是直接树链剖分然后用区间修改区间查询树状数组(我写的这种)或者线段树来维护吧。。这样做是O(Nlog^2N)的。
但是还可以做到O(NlogN)。首先可以发现它是单点链上查询,那么可以考虑用差分的思想,或者考虑将单点修改直接变成区间修改然后就只用单点简单查询了。
首先考虑单点修改,这种操作只对它所在的子树中的所有点的答案有影响,也就是所在的子树中每一个点的答案+a,这个可以用dfs序列转化为区间修改。
然后考虑对子树x的修改,那么对所在的子树中某一个点p,点p的答案+a*(d[p]-d[x]+1)=+a*d[p]+(a-a*d[x]),注意到括号中的部分是常数(即对每一个p来说相同),用上面的单点修改即可。然后我们还需要一个数组b(另外一个假设是a)维护每一个点的d[p]被加上了多少次。这样还是区间修改。
那么查询的答案就是ai+bi*d[i]了,直接上查分的树状数组转化为单点修改前缀查询。O(NlogN),这个应该是最快的写法了。
AC代码如下(树链剖分+区间修改区间查询树状数组):
#include<iostream> #include<cstdio> #include<cstring> #define ll long long #define N 100005 using namespace std; int n,m,tot,dfsclk,a[N],fst[N],pnt[N<<1],nxt[N<<1],bg[N],ed[N],fa[N],anc[N],son[N],sz[N]; ll c[2][N]; int read(){ int x=0,fu=1; char ch=getchar(); while (ch<'0' || ch>'9'){ if (ch=='-') fu=-1; ch=getchar(); } while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*fu; } void add(int x,int y){ pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot; } void ins(int k,int x,ll t){ for (; x<=n; x+=x&-x) c[k][x]+=t; } ll getsum(int k,int x){ ll sum=0; for (; x; x-=x&-x) sum+=c[k][x]; return sum; } void mdy(int x,int y,ll z){ ins(0,x,z); ins(0,y+1,-z); ins(1,x,z*(x-1)); ins(1,y+1,-z*y); } ll qry(int x,int y){ return getsum(0,y)*y-getsum(1,y)-getsum(0,x-1)*(x-1)+getsum(1,x-1); } void dfs(int x){ sz[x]=1; int p; for (p=fst[x]; p; p=nxt[p]){ int y=pnt[p]; if (y!=fa[x]){ fa[y]=x; dfs(y); sz[x]+=sz[y]; if (sz[y]>sz[son[x]]) son[x]=y; } } } void divide(int x,int tp){ bg[x]=++dfsclk; anc[x]=tp; int p; if (son[x]) divide(son[x],tp); for (p=fst[x]; p; p=nxt[p]){ int y=pnt[p]; if (y!=son[x] && y!=fa[x]) divide(y,y); } ed[x]=dfsclk; } int main(){ n=read(); m=read(); int i,k,x,y; ll ans; for (i=1; i<=n; i++) a[i]=read(); for (i=1; i<n; i++){ x=read(); y=read(); add(x,y); add(y,x); } dfs(1); divide(1,1); for (i=1; i<=n; i++) mdy(bg[i],bg[i],a[i]); while (m--){ k=read(); if (k==1){ x=read(); y=read(); mdy(bg[x],bg[x],(ll)y); } else if (k==2){ x=read(); y=read(); mdy(bg[x],ed[x],(ll)y); } else{ x=read(); ans=0; for (; x; x=fa[anc[x]]) ans+=qry(bg[anc[x]],bg[x]); printf("%lld\n",ans); } } return 0; }
by lych
2016.3.14