BZOJ4999 This Problem Is Too Simple!(树上差分+dfs序+树状数组)
对每个权值分别考虑。则只有单点加路径求和的操作。树上差分转化为求到根的路径和,子树加即可。再差分后bit即可。注意树上差分中根的父亲是0,已经忘了是第几次因为这个挂了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N],p[N],dfn[N],size[N],deep[N],fa[N][19],tree[N],ans[N*5],t,cnt; struct data{int to,nxt; }edge[N<<1]; struct data2 { int op,i,j,x,id; bool operator <(const data2&a) const { return x<a.x||x==a.x&&id<a.id; } }q[N*5]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { dfn[k]=++cnt,size[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=fa[k][0]) { deep[edge[i].to]=deep[k]+1; fa[edge[i].to][0]=k; dfs(edge[i].to); size[k]+=size[edge[i].to]; } } void add(int k,int x){while (k<=n) tree[k]+=x,k+=k&-k;} int query(int k) {int s=0;while (k) s+=tree[k],k-=k&-k;return s;} int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); for (int j=18;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j]; if (x==y) return x; for (int j=18;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; return fa[x][0]; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4999.in","r",stdin); freopen("bzoj4999.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif 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(); addedge(x,y),addedge(y,x); } fa[1][0]=1;dfs(1); for (int j=1;j<19;j++) for (int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; int x=0; for (int i=1;i<=n;i++) x++,q[x].op=0,q[x].i=i,q[x].j=1,q[x].x=a[i],q[x].id=x; for (int i=1;i<=m;i++) { char c=getc(); if (c=='C') { x++,q[x].op=0,q[x].i=read(),q[x].j=1,q[x].x=read(),q[x].id=x; x++,q[x].op=0,q[x].i=q[x-1].i,q[x].j=-1,q[x].x=a[q[x].i],q[x].id=x; a[q[x].i]=q[x-1].x; } else x++,q[x].op=1,q[x].i=read(),q[x].j=read(),q[x].x=read(),q[x].id=x; } m=x; sort(q+1,q+m+1);memset(ans,255,sizeof(ans)); for (int i=1;i<=m;i++) { int t=i; while (t<m&&q[t+1].x==q[i].x) t++; for (int j=i;j<=t;j++) if (q[j].op) { int l=lca(q[j].i,q[j].j); ans[q[j].id]=query(dfn[q[j].i])+query(dfn[q[j].j])-query(dfn[l])-query(dfn[l==1?0:fa[l][0]]); } else add(dfn[q[j].i],q[j].j),add(dfn[q[j].i]+size[q[j].i],-q[j].j); for (int j=i;j<=t;j++) if (q[j].op==0) add(dfn[q[j].i],-q[j].j),add(dfn[q[j].i]+size[q[j].i],q[j].j); i=t; } for (int i=1;i<=m;i++) if (ans[i]>=0) printf("%d\n",ans[i]); return 0; }