天天看點

洛谷 3979 BZOJ 3083 遙遠的國度

【題解】

  這道題除去根操作就是普通的樹鍊剖分了。但是有換根操作怎麼處理呢?

  我們可以發現如果現在的根不在查詢的點的子樹裡,那麼對本次查詢沒有影響。如果現在的跟在查詢的點x的子樹裡,那麼答案将變為整棵樹除去現在的根root所屬的x的孩子的子樹。

  為了快速确定root屬于x的哪一個孩子,我們可以寫個倍增。

1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cmath>
  5 #define N 200010
  6 #define LL long long
  7 #define rg register
  8 #define ls (u<<1)
  9 #define rs (u<<1|1)
 10 #define mid ((a[u].l+a[u].r)>>1)
 11 using namespace std;
 12 int n,m,tot,cnt,root=1,last[N],dep[N],siz[N],top[N],fa[N],hvy[N],dfn[N],pos[N],v[N],p[N][20];
 13 struct edge{
 14     int to,pre;
 15 }e[N<<1];
 16 struct tree{
 17     int l,r,mn,num; bool mark;
 18 }a[N<<2];
 19 inline int read(){
 20     int k=0,f=1; char c=getchar();
 21     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
 22     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
 23     return k*f;
 24 }
 25 void find(int u,int f){
 26     p[u][0]=f;
 27     for (int i=1;i<=log2(dep[u]);i++) p[u][i]=p[p[u][i-1]][i-1];
 28     for (int i=last[u],to=e[i].to;i;i=e[i].pre,to=e[i].to)
 29     if(to!=f) find(to,u);
 30 }
 31 void dfs1(int x){
 32     siz[x]=1; dep[x]=dep[fa[x]]+1;
 33     for(rg int i=last[x],to;i;i=e[i].pre)if((to=e[i].to)!=fa[x]){
 34         fa[to]=x; dfs1(to); siz[x]+=siz[to];
 35         if(siz[x]>siz[hvy[x]]) hvy[x]=to;
 36     }
 37 }
 38 void dfs2(int x,int tp){
 39     top[x]=tp; dfn[x]=++cnt; pos[cnt]=x;
 40     if(hvy[x]) dfs2(hvy[x],tp);
 41     for(rg int i=last[x],to;i;i=e[i].pre)if((to=e[i].to)!=fa[x]&&to!=hvy[x]) 
 42         dfs2(to,to);
 43 }
 44 void build(int u,int l,int r){
 45     a[u].l=l; a[u].r=r;
 46     if(l<r) build(ls,l,mid),build(rs,mid+1,r),a[u].mn=min(a[ls].mn,a[rs].mn);
 47     else a[u].mn=v[pos[l]];
 48 }
 49 inline void pushdown(int u){
 50     a[u].mark=0; a[ls].mark=a[rs].mark=1;
 51     a[ls].num=a[rs].num=a[u].num;
 52     a[ls].mn=a[rs].mn=a[u].mn;
 53 }
 54 void update(int u,int l,int r,int d){
 55     if(l<=a[u].l&&a[u].r<=r){
 56         a[u].mark=1; a[u].num=d; a[u].mn=d;
 57         return;
 58     }
 59     if(a[u].mark) pushdown(u);
 60     if(l<=mid) update(ls,l,r,d);
 61     if(r>mid) update(rs,l,r,d);
 62     a[u].mn=min(a[ls].mn,a[rs].mn);
 63 }
 64 int query(int u,int l,int r){
 65     if(l<=a[u].l&&a[u].r<=r) return a[u].mn;
 66     if(a[u].mark) pushdown(u); int ret=2e9;
 67     if(l<=mid) ret=min(ret,query(ls,l,r));
 68     if(r>mid) ret=min(ret,query(rs,l,r));
 69     return ret;
 70 }
 71 int main(){
 72     n=read(); m=read();
 73     for(rg int i=1;i<n;i++){
 74         int u=read(),v=read();
 75         e[++tot]=(edge){v,last[u]}; last[u]=tot;
 76         e[++tot]=(edge){u,last[v]}; last[v]=tot;
 77     }
 78     for(rg int i=1;i<=n;i++) v[i]=read();
 79     root=read();
 80     dfs1(root); dfs2(root,root); build(1,1,n); find(root,0);
 81     while(m--){
 82         int opt=read();
 83         if(opt==1) root=read();
 84         else if(opt==2){
 85             int x=read(),y=read(),d=read(),t1=top[x],t2=top[y];
 86             while(t1!=t2){
 87                 if(dep[t1]<dep[t2]) swap(t1,t2),swap(x,y);
 88                 update(1,dfn[t1],dfn[x],d);
 89                 x=fa[t1]; t1=top[x];
 90             }
 91             if(dep[x]>dep[y]) swap(x,y); 
 92             update(1,dfn[x],dfn[y],d);
 93         }
 94         else if(opt==3){
 95             int x=read();
 96             if(dfn[x]<dfn[root]&&dfn[root]<=dfn[x]+siz[x]-1){
 97                 int y=root;
 98                 for(int i=log2(dep[y]-dep[x]);i>=0&&(dep[x]+1)!=dep[y];i--)
 99                     if(dep[p[y][i]]>=dep[x]+1) y=p[y][i];
100                 int ans=2e9;
101                 ans=min(ans,query(1,1,dfn[y]-1));
102                 ans=min(ans,query(1,dfn[y]+siz[y],n));
103                 printf("%d
",ans);
104             }
105             else{
106                 if(x==root) printf("%d
",query(1,1,n));
107                 else printf("%d
",query(1,dfn[x],dfn[x]+siz[x]-1));
108             }
109         }
110     }
111     return 0;
112 }      

View Code