首页 > 代码库 > bzoj 3083 树链剖分
bzoj 3083 树链剖分
首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区间,后者询问区间的补集。
/************************************************************** Problem: 3083 User: BLADEVIL Language: C++ Result: Accepted Time:6412 ms Memory:43904 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <algorithm> #define maxn 200010 #define maxm 400010 #define inf (~0U>>1) using namespace std; struct segment_tree { int left,right,min_,lazy; }t[maxn<<2]; int n,m,l,rot,tot; int key[maxn]; int other[maxm],pre[maxm],last[maxn]; int size[maxn],max_son[maxn],top[maxn],dep[maxn],a[maxn],num[maxn][2],jump[maxn][20],dis[maxn]; void connect(int x,int y) { pre[++l]=last[x]; last[x]=l; other[l]=y; } void update(int x) { t[x].min_=min(t[x<<1].min_,t[(x<<1)+1].min_); } void push_down(int x) { t[x<<1].lazy=t[(x<<1)+1].lazy=t[x].lazy; t[x<<1].min_=t[(x<<1)+1].min_=t[x].min_; t[x].lazy=0; } int get_lca(int x,int y) { if (dis[x]>dis[y]) swap(x,y); int det=dis[y]-dis[x]; for (int j=0;j<=18;j++) if (det&(1<<j)) y=jump[y][j]; if (x==y) return x; for (int j=18;j>=0;j--) if (jump[x][j]!=jump[y][j]) x=jump[x][j],y=jump[y][j]; return jump[x][1]; } int get_lca_son(int x,int y) { if (dis[x]>dis[y]) swap(x,y); for (int j=18;j>=0;j--) if (dis[jump[y][j]]>dis[x]) y=jump[y][j]; return y; } void dfs(int x) { size[x]=1; for (int p=last[x];p;p=pre[p]) { if (dis[other[p]]) continue; jump[other[p]][0]=x; dis[other[p]]=dis[x]+1; dfs(other[p]); size[x]+=size[other[p]]; if (size[other[p]]>size[max_son[x]]) max_son[x]=other[p]; } } void make_segment(int x) { num[x][0]=++tot; a[tot]=key[x]; if (max_son[x]) { top[max_son[x]]=top[x]; dep[max_son[x]]=dep[x]; make_segment(max_son[x]); } for (int p=last[x];p;p=pre[p]) { if (other[p]==jump[x][0]) continue; if (other[p]==max_son[x]) continue; top[other[p]]=other[p]; dep[other[p]]=dep[x]+1; make_segment(other[p]); } num[x][1]=tot; } void build_segment(int x,int l,int r) { t[x].left=l; t[x].right=r; if (t[x].left==t[x].right) { t[x].min_=a[t[x].left]; return ; } int mid=t[x].left+t[x].right>>1; build_segment(x<<1,l,mid); build_segment((x<<1)+1,mid+1,r); update(x); } void change_segment_tree(int x,int l,int r,int y) { if (t[x].lazy) push_down(x); if ((t[x].left==l)&&(t[x].right==r)) { t[x].lazy=t[x].min_=y; return ; } int mid=t[x].left+t[x].right>>1; if (l>mid) change_segment_tree((x<<1)+1,l,r,y); else if (r<=mid) change_segment_tree(x<<1,l,r,y); else change_segment_tree(x<<1,l,mid,y),change_segment_tree((x<<1)+1,mid+1,r,y); update(x); } void change(int x,int y,int z) { if (dep[x]>dep[y]) swap(x,y); while (dep[x]!=dep[y]) { change_segment_tree(1,num[top[y]][0],num[y][0],z); y=jump[top[y]][0]; } while (top[x]!=top[y]) { change_segment_tree(1,num[top[x]][0],num[x][0],z); change_segment_tree(1,num[top[y]][0],num[y][0],z); x=jump[top[x]][0]; y=jump[top[y]][0]; } if (num[x][0]>num[y][0]) swap(x,y); change_segment_tree(1,num[x][0],num[y][0],z); } int query_segment_tree(int x,int l,int r) { if (l>r) return inf; if (t[x].lazy) push_down(x); if ((t[x].left==l)&&(t[x].right==r)) return t[x].min_; int mid=t[x].left+t[x].right>>1; if (l>mid) return query_segment_tree((x<<1)+1,l,r); else if (r<=mid) return query_segment_tree(x<<1,l,r); else return min(query_segment_tree(x<<1,l,mid),query_segment_tree((x<<1)+1,mid+1,r)); } void query(int x) { if (x==rot) { printf("%d\n",t[1].min_); return ; } if (get_lca(x,rot)!=x) printf("%d\n",query_segment_tree(1,num[x][0],num[x][1])); else { int y=get_lca_son(x,rot); printf("%d\n",min(query_segment_tree(1,1,num[y][0]-1),query_segment_tree(1,num[y][1]+1,n))); //printf("%d %d\n",query_segment_tree(1,1,num[y][0]-1),query_segment_tree(1,num[y][1]+1,n)); //printf("%d\n",y); //printf("%d %d\n",num[y][0],num[y][1]); } } int main() { //freopen("country.in","r",stdin); freopen("country.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); connect(x,y); connect(y,x); } for (int i=1;i<=n;i++) scanf("%d",&key[i]); scanf("%d",&rot); dis[rot]=1; dfs(rot); top[rot]=rot; dep[rot]=1; make_segment(rot); //for (int i=1;i<=n;i++) printf("%d %d %d %d %d\n",i,max_son[i],size[i],num[i][0],num[i][1]); build_segment(1,1,n); for (int j=1;j<=18;j++) for (int i=1;i<=n;i++) jump[i][j]=jump[jump[i][j-1]][j-1]; while (m--) { int opt; scanf("%d",&opt); if (opt==1) scanf("%d",&rot); else if (opt==2) { int l,r,y; scanf("%d%d%d",&l,&r,&y); change(l,r,y); } else { int x; scanf("%d",&x); query(x); } } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。