BZOJ4448 SCOI2015情报传递(离线+树链剖分+树状数组)
即滋磁单点修改,询问路径上小于某数的值有多少个。暴力树剖套个主席树(或者直接树上主席树,似乎就1个log了?感觉不一定比两个log快)即可,然而不太优美。
开始觉得可以cdq,然而就变成log^3了。冷静一下感觉简直是个弱智,修改本身就是单调的,只要对询问离线即可。树剖+BIT即可维护。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; 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; } #define N 200010 int n,m,root,fa[N],deep[N],p[N],t=0,cnt,cntu,cntq; int top[N],id[N],son[N],size[N],tree[N]; struct data{int to,nxt; }edge[N]; struct data2{int x,i; }u[N]; struct data3{int x,y,z,i,ans; }q[N]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} bool cmp(const data3&a,const data3&b) { return a.z<b.z; } bool cmp1(const data3&a,const data3&b) { return a.i<b.i; } void dfs1(int k) { size[k]=1; for (int i=p[k];i;i=edge[i].nxt) { deep[edge[i].to]=deep[k]+1; dfs1(edge[i].to); size[k]+=size[edge[i].to]; if (size[edge[i].to]>size[son[k]]) son[k]=edge[i].to; } } void dfs2(int k,int from) { top[k]=from;id[k]=++cnt; if (son[k]) dfs2(son[k],from); for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=son[k]) dfs2(edge[i].to,edge[i].to); } void mbit(int k){while (k<=n) tree[k]++,k+=k&-k;} int qbit(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;} int lca(int x,int y) { while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x,y); x=fa[top[x]]; } return deep[x]<deep[y]?x:y; } int query(int x,int y) { int s=0; while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x,y); s+=qbit(id[x])-qbit(id[top[x]]-1); x=fa[top[x]]; } if (deep[x]<deep[y]) swap(x,y); s+=qbit(id[x])-qbit(id[y]-1); return s; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4448.in","r",stdin); freopen("bzoj4448.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) { fa[i]=read(); if (fa[i]==0) root=i,fa[i]=i; else addedge(fa[i],i); } dfs1(root); dfs2(root,root); m=read(); for (int i=1;i<=m;i++) { int op=read(); if (op==1) cntq++,q[cntq].x=read(),q[cntq].y=read(),q[cntq].z=i-read()-1,q[cntq].i=i; else cntu++,u[cntu].x=read(),u[cntu].i=i; } sort(q+1,q+cntq+1,cmp); int x=0; for (int i=1;i<=cntq;i++) if (q[i].z>0) { while (x<cntu&&u[x+1].i<=q[i].z) mbit(id[u[++x].x]); q[i].ans=query(q[i].x,q[i].y); } sort(q+1,q+cntq+1,cmp1); for (int i=1;i<=cntq;i++) printf("%d %d\n",deep[q[i].x]+deep[q[i].y]-(deep[lca(q[i].x,q[i].y)]<<1)+1,q[i].ans); return 0; }