您现在的位置是:主页 > news > 企业网站的网络营销功能/网站优化排名易下拉系统
企业网站的网络营销功能/网站优化排名易下拉系统
admin2025/6/7 18:00:42【news】
简介企业网站的网络营销功能,网站优化排名易下拉系统,网站开发相关知识,广西南宁网站建设因为今天是植树节,所以我们要剖树 题目: 我是超链接 题解: 可以发现除了这个换根操作之外别的全是裸树剖dfs序维护子树 换根的情况怎么办呢?我们可以分类讨论一下,假如说这次要查询x的子树 rootx,那么…
企业网站的网络营销功能,网站优化排名易下拉系统,网站开发相关知识,广西南宁网站建设因为今天是植树节,所以我们要剖树 题目:
我是超链接
题解:
可以发现除了这个换根操作之外别的全是裸树剖dfs序维护子树 换根的情况怎么办呢?我们可以分类讨论一下,假如说这次要查询x的子树
rootx,那么…
因为今天是植树节,所以我们要剖树
题目:
我是超链接
题解:
可以发现除了这个换根操作之外别的全是裸树剖+dfs序维护子树
换根的情况怎么办呢?我们可以分类讨论一下,假如说这次要查询x的子树
- root=x,那么查询的范围是整棵树
- root不在x的子树里,那么对x的查询范围并没有什么影响,还是in~out
- root在x的子树里,那么需要查询的部分是除了通往root这一支之外的最小值
有一个小细节要注意,判断以上的第三种情况时,不能用【除了子树里有root的v[i],别的都加上】,而是用【把这一支找出来然后求补集】,因为如果把其他的都加上,如果遇到fa[x]就很麻烦了,你加还是不加?加的话就白分类了,不加就少了一支,所以要用补集法
代码:
#include <cstdio>
#include <iostream>
#define INF 2147483647
using namespace std;
const int N=100005;
int tot,nxt[N*2],point[N],v[N*2],fa[N],h[N],in[N],out[N],top[N];
int n,delta[N*4],son[N],minn[N*4],root,size[N],totw,a[N],tree[N];
void addline(int x,int y)
{++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs_1(int x,int faa)
{fa[x]=faa;h[x]=h[faa]+1;size[x]=1;int maxx=0;for (int i=point[x];i;i=nxt[i])if (v[i]!=faa){dfs_1(v[i],x);size[x]+=size[v[i]];if (maxx<size[v[i]]) maxx=size[v[i]],son[x]=v[i];}
}
void dfs_2(int x,int fa)
{if (son[fa]!=x) top[x]=x;else top[x]=top[fa];in[x]=++totw;if (son[x]){dfs_2(son[x],x);for (int i=point[x];i;i=nxt[i])if (v[i]!=fa && v[i]!=son[x]) dfs_2(v[i],x);} out[x]=totw;
}
void updata(int now){minn[now]=min(minn[now<<1],minn[now<<1|1]);}
void pushdown(int now)
{if (delta[now]){delta[now<<1]=delta[now];delta[now<<1|1]=delta[now];minn[now<<1]=delta[now];minn[now<<1|1]=delta[now];delta[now]=0;}
}
void build(int now,int l,int r)
{if (l==r){minn[now]=a[tree[l]];return;}int mid=(l+r)>>1;build(now<<1,l,mid);build(now<<1|1,mid+1,r);updata(now);
}
void change(int now,int l,int r,int lrange,int rrange,int vv)
{if (lrange<=l && rrange>=r) {delta[now]=vv; minn[now]=vv;return;}int mid=(l+r)>>1;pushdown(now);if (lrange<=mid) change(now<<1,l,mid,lrange,rrange,vv);if (rrange>mid) change(now<<1|1,mid+1,r,lrange,rrange,vv);updata(now);
}
int qurry(int now,int l,int r,int lrange,int rrange)
{if (lrange<=l && rrange>=r) return minn[now];int mid=(l+r)>>1,ans=INF;pushdown(now);if (lrange<=mid) ans=min(ans,qurry(now<<1,l,mid,lrange,rrange));if (rrange>mid) ans=min(ans,qurry(now<<1|1,mid+1,r,lrange,rrange));return ans;
}
void Chan(int u,int v,int vv)
{int f1=top[u],f2=top[v];while (f1!=f2){if (h[f1]<h[f2]) swap(f1,f2),swap(u,v);change(1,1,n,in[f1],in[u],vv);u=fa[f1]; f1=top[u];}if (in[u]>in[v]) swap(u,v);change(1,1,n,in[u],in[v],vv);
}
int Qu(int x)
{if (root==x) return qurry(1,1,n,1,n);if (in[root]<in[x] || in[root]>out[x]) return qurry(1,1,n,in[x],out[x]); //root不在x的子树里 int Min=INF;for (int i=point[x];i;i=nxt[i])if (v[i]!=fa[x] && in[root]>=in[v[i]] && in[root]<=out[v[i]]) //root在v[i]的子树里 {if (in[v[i]]>1) Min=min(Min,qurry(1,1,n,1,in[v[i]]-1));//转换为补集一次求解 if (out[v[i]]<n) Min=min(Min,qurry(1,1,n,out[v[i]]+1,n));}return Min;
}
int main()
{int m;scanf("%d%d",&n,&m);for (int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addline(x,y);}for (int i=1;i<=n;i++) scanf("%d",&a[i]);scanf("%d",&root);dfs_1(root,0); dfs_2(root,0);for (int i=1;i<=n;i++) tree[in[i]]=i;build(1,1,n);while (m--){int opt,x,y,v;scanf("%d",&opt); switch(opt){case 1:scanf("%d",&root);break;case 2:scanf("%d%d%d",&x,&y,&v);Chan(x,y,v);break;case 3:scanf("%d",&x);printf("%d\n",Qu(x));break;}}
}