BZOJ4765: 普通計算姬
阿新 • • 發佈:2019-02-15
怎麽 sign online 連續 getchar printf 分析 dfs open
BZOJ4765: 普通計算姬
題目描述
傳送門
題目分析
求的和非常奇怪,不具有連續性,所有上樹的數據結構全死了。
考慮分塊,思考對於一段連續的詢問區間可以直接詢問整塊,零散塊可以在樹上dfs序暴力求出。
使用預處理打標記的方式搞定每個點對每個塊的影響是多少。這樣修改的時候直接針對差值相應變動每個塊的值就可以了。
那麽dfs序上的值應該怎麽快速查詢,可以對dfs序進行另外的分塊,同時使用前綴和來快速回答每一組詢問。時間復雜度就可以平衡到\(O(\sqrt n)\)
是代碼呢
#include <bits/stdc++.h> using namespace std; const int MAXN=1e5+7; #define LL long long #define ull unsigned long long int n,m,rt,cnt,num; LL qian[MAXN],a[MAXN],c[MAXN],s[MAXN],sk[MAXN]; int head[MAXN],block,kcnt,S[MAXN][350],L[MAXN],R[MAXN],belong[MAXN],pre[MAXN],last[MAXN],dfn[MAXN],f[MAXN]; bool in[MAXN]; struct po{ int nxt,to; }edge[MAXN<<1]; ull ans,sum[MAXN]; //vector<int>edge[MAXN]; inline void add_edge(int from,int to) { edge[++num].nxt=head[from];edge[num].to=to;head[from]=num; edge[++num].nxt=head[to];edge[num].to=from;head[to]=num; } inline void add(int x,LL val) { for(int i=x;i<=R[belong[x]];i++) s[i]+=val; for(int i=belong[x];i<=kcnt;i++) c[i]+=val; } inline LL query(int l,int r) { LL tot=0;int ll=belong[l],rr=belong[r]; if(belong[l]==belong[r]){ if(l==L[ll]) tot=s[r]; else tot=s[r]-s[l-1]; return tot; } if(l!=L[ll]){ tot+=s[L[ll+1]-1]-s[l-1]; ll++; } if(r!=R[rr]){ tot+=s[r]; rr--; } if(ll<=rr) tot+=c[rr]-c[ll-1]; return tot; } inline void dfs(int u,int fa) { dfn[u]=++num;pre[num]=u; // for(int i=0;i<edge[u].size();i++){ // int v=edge[u][i]; // if(v==fa) continue; // dfs(v,u); // } for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(v==fa) continue; dfs(v,u); } last[u]=num; } inline void dfs2(int u,int fa,int lei,int k) { if(in[u]) lei++; S[u][k]=lei; // for(int i=0;i<edge[u].size();i++){ // int v=edge[u][i]; // if(v==fa) continue; // dfs2(v,u,lei,k); // } for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(v==fa) continue; dfs2(v,u,lei,k); } } inline void build() { num=0; dfs(rt,0); block=330; for(int i=1;i<=n;i++) qian[i]=qian[i-1]+a[pre[i]]; for(int i=1;i<=n;i++) belong[i]=(i-1)/block+1; kcnt=n/block+(n%block==0?0:1); for(int i=1;i<=n;i++) if(!L[belong[i]]) L[belong[i]]=i; for(int i=n;i;i--) if(!R[belong[i]]) R[belong[i]]=i; L[kcnt+1]=n+1; for(int i=1;i<=kcnt;i++){ s[L[i]]=a[pre[L[i]]]; c[i]=c[i-1]+a[pre[L[i]]]; for(int j=L[i]+1;j<=R[i];j++){ c[i]+=a[pre[j]]; s[j]=s[j-1]+a[pre[j]]; } } for(int i=1;i<=kcnt;i++){ for(int j=L[i];j<=R[i];j++){ in[j]=1; sum[i]+=qian[last[j]]-qian[dfn[j]-1]; } dfs2(rt,0,0,i); for(int j=L[i];j<=R[i];j++) in[j]=0; } } inline int read() { int x=0,c=1; char ch=' '; while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); while(ch=='-')c*=-1,ch=getchar(); while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*c; } int main() { // freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++){ int x=read(),y=read(); if(x>y) swap(x,y); if(x==0){rt=y;continue;} // edge[x].push_back(y),edge[y].push_back(x); add_edge(x,y); } build(); int ll,rr; LL C; while(m--){ int opt=read(),x=read(),y=read(); if(opt==1){ int C=y-a[x]; add(dfn[x],y-a[x]); for(int i=1;i<=kcnt;i++) sum[i]+=1ll*C*S[x][i]; a[x]=y; } else { ans=0; if(belong[x]==belong[y]||belong[x]==belong[y]-1){ for(int i=x;i<=y;i++) ans+=query(dfn[i],last[i]); } else { if(x==L[belong[x]]) ll=belong[x]; else ll=belong[x]+1; if(y==R[belong[y]]) rr=belong[y]; else rr=belong[y]-1; for(int i=ll;i<=rr;i++) ans+=sum[i]; for(int i=x;i<L[ll];i++) ans+=query(dfn[i],last[i]); for(int i=R[rr]+1;i<=y;i++) ans+=query(dfn[i],last[i]); } printf("%llu\n", ans); } } }
BZOJ4765: 普通計算姬