[虚树][树状数组]JZOJ 5908 开荒
分析
由于询问点少,我们考虑建虚树(假
然后用树状数组维护关键节点的和就行了
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #define lowbit(x) x&-x using namespace std; typedef long long ll; const int N=1e5+10; struct Edge { int u,v,nx; }g[2*N]; int cnt,list[N]; ll c[N],w[N]; int st[N],ed[N],tme; int dep[N],f[N][21]; int a[2*N],acnt; int n,q; void Addedge(int u,int v) { g[++cnt].u=u;g[cnt].v=v;g[cnt].nx=list[u];list[u]=cnt; } int LCA(int u,int v) { if (dep[u]<dep[v]) swap(u,v); for (int i=20;i>=0;i--) if (dep[f[u][i]]>=dep[v]) u=f[u][i]; if (u==v) return u; for (int i=20;i>=0;i--) if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; return f[u][0]; } void Dfs(int u,int fa) { st[u]=++tme;dep[u]=dep[fa]+1; for (int i=1;i<=20;i++) f[u][i]=f[f[u][i-1]][i-1]; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) { f[g[i].v][0]=u; Dfs(g[i].v,u); } ed[u]=tme; } void Add(int x,ll y) { for (int i=x;i<=n;i+=lowbit(i)) c[i]+=y; } ll Get_Sum(int x) { ll ans=0; for (int i=x;i;i-=lowbit(i)) ans+=c[i]; return ans; } bool Cmp(int a,int b) { return st[a]<st[b]; } int main() { freopen("kaihuang.in","r",stdin); freopen("kaihuang.out","w",stdout); scanf("%d%d",&n,&q); for (int i=1;i<=n;i++) scanf("%lld",&w[i]); for (int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); Addedge(u,v);Addedge(v,u); } Dfs(1,0); for (int i=1;i<=n;i++) Add(st[i],w[i]),Add(ed[i]+1,-w[i]); for (int i=1;i<=q;i++) { char c; do { scanf("%c",&c); } while (c!='C'&&c!='Q'); if (c=='C') { int a;ll b; scanf("%d%lld",&a,&b); Add(st[a],b-w[a]);Add(ed[a]+1,w[a]-b); w[a]=b; continue; } acnt=0; do { acnt++; scanf("%d",&a[acnt]); } while (a[acnt]!=0); acnt--; sort(a+1,a+acnt+1,Cmp); int fakeacnt=acnt; for (int i=1;i<fakeacnt;i++) a[++acnt]=LCA(a[i],a[i+1]); sort(a+1,a+acnt+1,Cmp);acnt=unique(a+1,a+acnt+1)-a-1; stack<int> stk; ll ans=0; while (!stk.empty()) stk.pop(); for (int i=1;i<=acnt;i++) { for (;!stk.empty()&&ed[stk.top()]<st[a[i]];stk.pop()); ans+=!stk.empty()?Get_Sum(st[a[i]])-Get_Sum(st[stk.top()]):w[a[i]]; stk.push(a[i]); } printf("%lld\n",ans); } }
在日渐沉没的世界里,我发现了你。