[虚树][树状数组][lca] Jzoj P5908 开荒
题解
- 题目大意,有q次操作,询问操作是求k个点两两到lca所经过点的点权和,修改操作就是修改一个点的点权
- 首先,求距离可以用树状数组按照dfs序加入,类似差分约束一样求
- 当然修改也可以
- 那么现在问题就是直接暴力两两lca做显然不行,要找一种更快的做法
- 可以建一棵虚树
- 然后对于虚树上的非父亲节点,直接求出他到父亲的点权和(不包括父亲),而对于父亲则直接加上自己的点权即可
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 const int N=2e5+10; 7 int n,Q,tot,num,cnt,p,w,head[N],v[N],be[N],en[N],fa[N],d[N],dep[N],f[N][20],k[N],q[N]; 8 long long sz[N],ans; 9 struct edge {int to,from;}e[N]; 10 void dfs(int x,int pre) 11 { 12 f[x][0]=fa[x]=pre,be[x]=++tot,d[x]=d[fa[x]]+1,dep[x]=dep[pre]+1; 13 for (int i=head[x];i;i=e[i].from) if (e[i].to!=pre) dfs(e[i].to,x); 14 en[x]=tot; 15 } 16 bool cmp(int x,int y) { return be[x]<be[y]; } 17 int getlca(int x,int y) 18 { 19 if (dep[x]<dep[y]) swap(x,y); 20 for (int i=18;i>=0;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i]; 21 if (x==y) return x; 22 for (int i=18;i>=0;i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 23 return f[x][0]; 24 } 25 void add(int x,int y) { for (;x<=n;x+=x&-x) sz[x]+=y; } 26 long long getsum(int x) 27 { 28 long long v=0; 29 for (;x;x-=x&-x) v+=sz[x]; 30 return v; 31 } 32 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt; } 33 int main() 34 { 35 //freopen("kaihuang.in","r",stdin),freopen("kaihuang.out","w",stdout); 36 scanf("%d%d",&n,&Q); 37 for (int i=1;i<=n;i++) scanf("%d",&v[i]); 38 for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y),insert(y,x); 39 dfs(1,0); 40 for (int j=1;j<=19;j++) for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; 41 for (int i=1;i<=n;i++) add(be[i],v[i]),add(en[i]+1,-v[i]); 42 while (Q--) 43 { 44 scanf("\n"); 45 char ch=getchar(); int x,y; 46 if (ch=='C') 47 { 48 scanf("%d%d",&x,&y),y-=v[x],v[x]+=y; 49 add(be[x],y),add(en[x]+1,-y); 50 } 51 else 52 { 53 num=1,p=0; scanf("%d",&k[num]); while (k[num]!=0) scanf("%d",&k[++num]); num--; 54 sort(k+1,k+num+1,cmp); 55 w=num; for (int i=1;i<=w-1;i++) k[++num]=getlca(k[i],k[i+1]); 56 sort(k+1,k+num+1,cmp),num=unique(k+1,k+num+1)-k-1; 57 ans=0; 58 for (int i=1;i<=num;i++) 59 { 60 for (;p&&en[q[p]]<be[k[i]];) p--; 61 ans+=p?getsum(be[k[i]])-getsum(be[q[p]]):v[k[i]]; 62 q[++p]=k[i]; 63 } 64 printf("%lld\n",ans); 65 } 66 } 67 }