【積累】【樹】2020牛客多校 A National Pandemic(樹剖)
阿新 • • 發佈:2020-08-07
題意
一棵樹 ,三種操作:
1,一箇中心城市 x,所有城市 y 的值+=w-dist(x,y)
2,將城市x的值與0取min
3,詢問單點的值。
官方題解
對於1操作,我們考慮一次修改對y來說會增加w-dis(x,y)
w-dis(x,y)=w-(dep[x]+dep[y]-2*dep[lca])=w-dep[x]-dep[y]+2dep[lca]
所以,對於每次1操作,我們將其到根上所有點的cnt+=2,詢問的時候那部分就是求它到根的權值和。
個人
不是程式碼不會敲,公式也會,但是就是想不到做法。看了題解才:哦哦哦哦哦!
唉,比賽時想了半天 一開始覺得是樹剖,想做,結果不知道怎麼下手,然後繞開樹剖繼續想。也就沒有然後了。
個人程式碼:
#pragma GCC optimize(2) #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int mod=998244353; const int inf=0x3f3f3f3f; const int maxn=5e4+5; const double ep=1e-6; void read(int&x) { char c; while(!isdigit(c=getchar()));x=c-'0'; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-'0'; } int n; vector<int>p[maxn]; int siz[maxn],dep[maxn],fad[maxn],son[maxn]; int top[maxn],tid[maxn],rnk[maxn],cnt; void dfs1(int u,int fa,int d) { dep[u]=d;fad[u]=fa;siz[u]=1;son[u]=0; for(int v:p[u]) { if(v==fa)continue; dfs1(v,u,d+1); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } void dfs2(int u,int t) { top[u]=t;tid[u]=++cnt;rnk[cnt]=u; if(!son[u])return; dfs2(son[u],t); for(int v:p[u]) if(v!=son[u]&&v!=fad[u]) dfs2(v,v); } struct Tr{ ll sum[maxn<<2],ly[maxn<<2]; inline void init(){mem(sum,0);mem(ly,0);} inline void pdown(int k,int l,int r){ int mid=(l+r)>>1; sum[k<<1]+=ly[k]*(mid-l+1);sum[k<<1|1]+=ly[k]*(r-mid); ly[k<<1]+=ly[k];ly[k<<1|1]+=ly[k]; ly[k]=0; } void update(int k,int l,int r,int L,int R,int v){ if(L>r||R<l)return; if(L<=l&&r<=R){ sum[k]+=1ll*v*(r-l+1);ly[k]+=v; return; } if(ly[k])pdown(k,l,r); int mid=(l+r)>>1; update(k<<1,l,mid,L,R,v);update(k<<1|1,mid+1,r,L,R,v); sum[k]=sum[k<<1]+sum[k<<1|1]; // printf("update(%d %d)=%lld\n",l,r,sum[k]); } ll query(int k,int l,int r,int L,int R){ if(L>r||R<l)return 0; if(L<=l&&r<=R)return sum[k]; if(ly[k])pdown(k,l,r); int mid=(l+r)>>1; return query(k<<1,l,mid,L,R)+query(k<<1|1,mid+1,r,L,R); } void tupdate(int u,int v,int w){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); update(1,1,n,tid[top[u]],tid[u],w); u=fad[top[u]]; } if(dep[u]>dep[v])swap(u,v); update(1,1,n,tid[u],tid[v],w); } ll tquery(int u,int v){ ll ans=0; while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); ans+=query(1,1,n,tid[top[u]],tid[u]); u=fad[top[u]]; } if(dep[u]>dep[v])swap(u,v); // printf("lastans=%lld,query<%d %d>\n",ans,tid[u],tid[v]); ans+=query(1,1,n,tid[u],tid[v]); return ans; } }st; ll f[maxn]; int main() { int T; read(T); while(T--) { int m,u,v;ll all=0,tim=0; read(n);read(m); for(int i=1;i<=n;i++)p[i].clear(),f[i]=0; for(int i=1;i<n;i++) { read(u);read(v); p[u].push_back(v);p[v].push_back(u); } cnt=0;dfs1(1,0,1);dfs2(1,1);st.init(); // for(int i=1;i<=n;i++)printf("%d ",tid[i]);putchar(10); int op,x,w; while(m--) { read(op); if(op==1){ read(x);read(w);all+=w-dep[x];tim++; st.tupdate(1,x,2); }else if(op==2){ read(x); ll ans=all-f[x]-tim*dep[x]; ans+=st.tquery(1,x); if(ans>0)f[x]+=ans; }else{ read(x); ll ans=all-f[x]-tim*dep[x]; ans+=st.tquery(1,x); // printf("(%lld)",st.tquery(1,x)); printf("%lld\n",ans); } } } }