图论/树 专题

就是一道树剖的裸题 实话说树剖细节挺多的
我打这个代码的时候遗漏的细节
1;有重儿子才先进行重儿子遍历 比如叶节点没有重儿子(默认为0) 是不能遍历的 不然会死循环
2;初始赋值的时候 是对1-n这有序的线段树进行赋值 所以有个rk[] 这个非常易错!!!! 出题人比较狡诈 样例能过
因为每个节点有个初始id 给出val的时候是有序的 让我们误以为直接赋值线段树就好 但是我们赋值是新的dfs序
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e5+5;
vector<int>Q[maxn];
int cnt,n,m;
struct node{
int l,r,maxx,sum;
}tr[maxn<<2];
int val[maxn],dfn[maxn],fa[maxn],top[maxn],sz[maxn],son[maxn],dp[maxn],rk[maxn];
void up(int);
void bd(int,int,int);
int qmax(int,int,int,int,int);
int qsum(int,int,int,int,int);
void upd(int,int,int,int,int);
int Qmax(int,int);
int Qsum(int,int);
void Upd(int,int);
void dfs1(int,int);
void dfs2(int,int);
int main(){
cin>>n;
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
Q[a].push_back(b);
Q[b].push_back(a);
}
for(int i=1;i<=n;i++)cin>>val[i];
fa[1]=1;
dfs1(1,1);
dfs2(1,1);
bd(1,1,n);
cin>>m;
while(m--){
string s;int a,b;
cin>>s>>a>>b;
if(s=="QMAX")cout<<Qmax(a,b)<<endl;
else if(s=="QSUM")cout<<Qsum(a,b)<<endl;
else upd(1,1,n,dfn[a],b);
}
return 0;
}
void dfs1(int u,int f){
sz[u]=1;
for(int i=0;i<Q[u].size();i++){
int to=Q[u][i];
if(to==f)continue;
dp[to]=dp[u]+1;fa[to]=u;
dfs1(to,u);
sz[u]+=sz[to];
if(sz[son[u]]<sz[to])son[u]=to;
}
}
void dfs2(int u,int tp){
top[u]=tp;dfn[u]=++cnt;rk[cnt]=u;
if(son[u]) //////
dfs2(son[u],tp);
for(int i=0;i<Q[u].size();i++){
int to=Q[u][i];
if(to==son[u]||to==fa[u])continue;
dfs2(to,to);
}
}
void up(int k){
tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
tr[k].maxx=max(tr[k<<1].maxx,tr[k<<1|1].maxx);
return;
}
void bd(int k,int l,int r){
if(r<l)return;
if(l==r){
tr[k].l=l,tr[k].r=r;
tr[k].sum=tr[k].maxx=val[rk[l]];/////
return;
}
int mid=l+r>>1;
bd(k<<1,l,mid);
bd(k<<1|1,mid+1,r);
up(k);
}
int qmax(int k,int l,int r,int L,int R){
if(L<=l&&r<=R)return tr[k].maxx;
int mid=l+r>>1;
int res=-1e9;
if(mid>=L)res=max(res,qmax(k<<1,l,mid,L,R));
if(mid<R)res=max(res,qmax(k<<1|1,mid+1,r,L,R));
up(k);
return res;
}
int qsum(int k,int l,int r,int L,int R){
if(L<=l&&r<=R)return tr[k].sum;
int mid=l+r>>1;
int res=0;
if(mid>=L)res+=qsum(k<<1,l,mid,L,R);
if(mid<R)res+=qsum(k<<1|1,mid+1,r,L,R);
up(k);
return res;
}
void upd(int k,int l,int r,int pos,int w){
if(l==r){
tr[k].maxx=tr[k].sum=w;
return;
}
int mid=l+r>>1;
if(pos<=mid)upd(k<<1,l,mid,pos,w);
else upd(k<<1|1,mid+1,r,pos,w);
up(k);
}
int Qsum(int u,int v){
int res=0;
while(top[u]!=top[v]){
if(dp[top[u]]<dp[top[v]])swap(u,v);
res+=qsum(1,1,n,dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
if(dp[u]<dp[v])swap(u,v);
res+=qsum(1,1,n,dfn[v],dfn[u]);
return res;
}
int Qmax(int u,int v){
int res=-1e9;
while(top[u]!=top[v]){
if(dp[top[u]]<dp[top[v]])swap(u,v);
res=max(res,qmax(1,1,n,dfn[top[u]],dfn[u]));
u=fa[top[u]];
}
if(dp[u]<dp[v])swap(u,v);
res=max(res,qmax(1,1,n,dfn[v],dfn[u]));
return res;
}


RMQ上维护最大和次大还是要注意一下的
点击查看代码
#include<bits/stdc++.h>
#define N 400010
#define M 900010
#define INF 2147483647000000
#define ll long long
using namespace std;
struct edge{
ll u,v,d;
ll next;
}G[N<<1];
ll tot=0;
ll head[N];
inline void addedge(ll u,ll v,ll d)
{
G[++tot].u=u,G[tot].v=v,G[tot].d=d,G[tot].next=head[u],head[u]=tot;
G[++tot].u=v,G[tot].v=u,G[tot].d=d,G[tot].next=head[v],head[v]=tot;
}
ll bz[N][19];
ll maxi[N][19];
ll mini[N][19];
ll deep[N];
inline void dfs(ll u,ll fa)
{
bz[u][0]=fa;
for(ll i=head[u];i;i=G[i].next)
{
ll v=G[i].v;
if(v==fa)continue;
deep[v]=deep[u]+1ll;
maxi[v][0]=G[i].d;
mini[v][0]=-INF;
dfs(v,u);
}
}
ll n;
inline void cal()
{
for(ll i=1;i<=18;++i)
for(ll j=1;j<=n;++j)
{
bz[j][i]=bz[bz[j][i-1]][i-1];
maxi[j][i]=max(maxi[j][i-1],maxi[bz[j][i-1]][i-1]);
mini[j][i]=max(mini[j][i-1],mini[bz[j][i-1]][i-1]);
if(maxi[j][i-1]>maxi[bz[j][i-1]][i-1])mini[j][i]=max(mini[j][i],maxi[bz[j][i-1]][i-1]);
else if(maxi[j][i-1]<maxi[bz[j][i-1]][i-1])mini[j][i]=max(mini[j][i],maxi[j][i-1]);
}
}
inline ll LCA(ll x,ll y)
{
if(deep[x]<deep[y])swap(x,y);
for(ll i=18;i>=0;--i)
if(deep[bz[x][i]]>=deep[y])
x=bz[x][i];
if(x==y)return x;
for(ll i=18;i>=0;--i)
if(bz[x][i]^bz[y][i])
x=bz[x][i],y=bz[y][i];
return bz[x][0];
}
inline ll qmax(ll u,ll v,ll maxx)
{
ll Ans=-INF;
for(ll i=18;i>=0;--i)
{
if(deep[bz[u][i]]>=deep[v])
{
if(maxx!=maxi[u][i])Ans=max(Ans,maxi[u][i]);
else Ans=max(Ans,mini[u][i]);
u=bz[u][i];
}
}
return Ans;
}
inline void read(ll &x)
{
x=0;
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+(ch^48),ch=getchar();
}
ll m;
edge A[M<<1];
inline bool cmp(edge x,edge y)
{
return x.d<y.d;
}
ll Father[N];
inline ll Get_Father(ll x)
{
return (x==Father[x]) ? x : Father[x]=Get_Father(Father[x]);
}
bool B[M<<1];
int main()
{
read(n),read(m);
for(ll i=1;i<=m;++i)
{
read(A[i].u),read(A[i].v),read(A[i].d);
}
sort(A+1,A+m+1,cmp);
for(ll i=1;i<=n;++i)
Father[i]=i;
ll Cnt=0ll;
for(ll i=1;i<=m;++i)
{
ll Father_u=Get_Father(A[i].u);
ll Father_v=Get_Father(A[i].v);
if(Father_u!=Father_v)
{
Cnt+=A[i].d;
Father[Father_u]=Father_v;
addedge(A[i].u,A[i].v,A[i].d);
B[i]=true;
}
}
mini[1][0]=-INF;
deep[1]=1;
dfs(1,-1);
cal();
ll Ans=INF;
for(ll i=1;i<=m;++i)
{
if(!B[i])
{
ll u=A[i].u;
ll v=A[i].v;
ll d=A[i].d;
ll lca=LCA(u,v);
ll maxu=qmax(u,lca,d);
ll maxv=qmax(v,lca,d);
Ans=min(Ans,Cnt-max(maxu,maxv)+d);
}
}
printf("%lld",Ans);
return 0;
}

针对瓶颈生成树 根据其充分性可以直接用最小生成树来解决

https://www.luogu.com.cn/problem/P3761

分析:
首先要删的边一定是在树的直径上 但这个题目枚举每一条边是没问题的
删去一条边后将一颗树变成了两颗树
对于每颗树内对答案的贡献为树的直径
现在问题变成了两棵树分别找一个点 <u,v> 使得对答案贡献最小
我们希望u为 u所在树中以u为终点 最长链最短 同理v
就是分别找两个树的半径 用换根dp即可
struct edge{
int v, w, id;
};
struct node{
int u, v, w;
};
vector<edge>g[N];
node e[N];
int n;
int del = 0;
int mx1[N], mx2[N], mx_child[N];
int maxd = 0;
void dfs_d(int u, int fa) {
mx1[u] = mx2[u] = 0;
for (auto ed : g[u]) {
if (ed.v == fa)continue;
if (ed.id == del)continue;
dfs_d(ed.v, u);
int val = mx1[ed.v] + ed.w;
if (val > mx1[u])mx2[u] = mx1[u], mx1[u] = val, mx_child[u] = ed.v;
else if (val > mx2[u]) mx2[u] = val;
}
maxd = max(maxd, mx1[u] + mx2[u]);
}
int maxr = 0;
void dfs_r(int u, int from, int fa) {
maxr = min(maxr, max( mx1[u],from ));
for (auto ed : g[u]) {
if (ed.v == fa)continue;
if (ed.id == del)continue;
if (ed.v == mx_child[u])
dfs_r(ed.v, max(from + ed.w, mx2[u] + ed.w), u);
else
dfs_r(ed.v, max(from + ed.w, mx1[u] + ed.w),u);
}
}
int get_d(int u) {
maxd = 0;
dfs_d(u, 0);
return maxd;
}
int get_r(int u) {
maxr = 1e9;
dfs_r(u, 0, 0);
return maxr;
}
void slove() {
cin >> n;
for (int i = 1; i <= n - 1; i++) {
int u, v, w; cin >> u >> v >> w;
e[i] = { u,v,w };
g[u].push_back({ v,w,i });
g[v].push_back({ u,w,i });
}
int ans = 1e9;
for (del = 1; del <= n - 1; del++) {
int u = e[del].u, v = e[del].v, w = e[del].w;
int res = max({
get_d(u),
get_d(v),
get_r(u) + get_r(v) + w
});
ans = min(ans, res);
}
cout << ans << endl;
}

浙公网安备 33010602011771号