EPIC Institute of Technology Round August 2024 D2. DFS Checker (Hard Version)(dfs序性质 lca)

题目

t(t<=1e4)组样例,每次给n(n<=3e5)个点的树,和一个初始dfs序序列,

q(q<=1e5)次交换,每次交换dfs序序列上的两个位置,问交换完是不是还是合法dfs序

思路来源

gongkoufadongji代码

题解

这题做法很多,很多也都是乱搞,补一个性质的做法

做法1

性质做法:lca(p[i],p[i-1])=fa(p[i])

考虑dfs序,每次要么是下钻一个点,要么是搜完一棵子树,跳到另一棵子树的根上

(1)下钻一个点的时候,满足a[i]是a[i-1]的儿子

(2)搜完一棵子树,跳到另一棵子树的根上,满足a[i]的父亲是a[i-1]的祖先,且a[i-1]是叶子

所以,只需满足性质的点是n-1个点,就是合法的dfs序

当然你也可以把相邻点距离也维护上,这样更卡不掉,距离总和是2n-2

做法2

做法2是赛中的想法,是一个乱搞,但是也卡不掉,感觉也挺对的

每个点u维护一个set,存所有直连儿子v的dfn,

考虑dfs序,dfn[u]一定是最小的直连dfn[v]减1,

最大的直连dfn[v]不会超过dfn[u]+sz[u]-sz[v]

https://codeforces.com/contest/2002/submission/275838298

代码1(dfs序性质 lca)

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define lowbit(x) (x&(-x))
#define ull unsigned long long 
#define pii pair<int,int>
using namespace std;
const string yes="Yes\n",no="No\n";
const int N = 1000005,inf = 2e18,mod=1000000007;
int n,q;
vector<int>p[300005];
int a[300005];
int st[300005][20];
int dep[300005];
void dfs(int u,int fa){
    dep[u]=dep[fa]+1;
    st[u][0]=fa;
    for(int i=1;i<20;i++){
        st[u][i]=st[st[u][i-1]][i-1];
    }
    for(auto v:p[u]){
        if(v==fa)continue;
        dfs(v,u);
    }

}
int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    for(int i=19;~i;i--){
        if(dep[st[u][i]]>=dep[v])u=st[u][i];
    }
    if(u==v)return u;
    for(int i=19;~i;i--){
        if(st[u][i]==st[v][i])continue;
        u=st[u][i];
        v=st[v][i];
    }
    return st[u][0];
}
int getdis(int u,int v){
    return min(u,v)>0?dep[u]+dep[v]-2*dep[lca(u,v)]:0;
}
int ck1(int x){
    return x<n&&x>0?lca(a[x],a[x+1])==a[x+1]:0;
}
void solve(){
    cin>>n>>q;
    for(int i=1;i<=n;i++){
        p[i].clear();
    }
    for(int i=2;i<=n;i++){
        int f;cin>>f;
        p[f].push_back(i);
    }
    dfs(1,0);
    int len=0,sum=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        len+=getdis(a[i],a[i-1]);
        sum+=ck1(i-1);
    }
    a[n+1]=0;
    while(q--){
        int u,v;cin>>u>>v;
        if(u>v)swap(u,v);
        len-=getdis(a[u],a[u-1]);
        len-=getdis(a[u],a[u+1]);
        len-=getdis(a[v],a[v-1]);
        len-=getdis(a[v],a[v+1]);
        sum-=ck1(u-1);
        sum-=ck1(u);
        if(u+1!=v)sum-=ck1(v-1);
        sum-=ck1(v);
        swap(a[u],a[v]);
        len+=getdis(a[u],a[u-1]);
        len+=getdis(a[u],a[u+1]);
        len+=getdis(a[v],a[v-1]);
        len+=getdis(a[v],a[v+1]);
        sum+=ck1(u-1);
        sum+=ck1(u);
        if(u+1!=v)sum+=ck1(v-1);
        sum+=ck1(v);
        // cout<<len<<"???\n";
        if(sum==0&&len+dep[a[n]]-1==2*n-2){
            cout<<yes;
        }
        else{
            cout<<no;
        }
    }


}
signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cout<<fixed<<setprecision(12);
    int t=1;
    cin>>t;
    while (t--)solve();
}

代码2(赛中想法)

#include <bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
const int N=3e5+10;
int t,n,Q,f,p[N],par[N],dfn[N],sz[N],x,y;
int no[N],cnt;
vector<int>e[N];
set<P>q[N];
void dfs(int u){
    sz[u]=1;
    for(auto &v:e[u]){
        dfs(v);
        sz[u]+=sz[v];
    }
}
void rb(int i){
    if(!i)return;
    if(q[i].empty())return;
    cnt-=no[i];
    int mn=(*q[i].begin()).fi;
    int mx=(*q[i].rbegin()).fi,w=(*q[i].rbegin()).se;
    if(dfn[i]!=mn-1 || mx<=dfn[i] || mx>dfn[i]+sz[i]-w)no[i]=1;
    else no[i]=0;
    cnt+=no[i];
}
int main(){
    sci(t);
    while(t--){
        sci(n);sci(Q);
        rep(i,0,n)q[i].clear(),e[i].clear(),no[i]=0;
        rep(i,2,n){
            sci(f);
            e[f].pb(i);
            par[i]=f;
        }
        dfs(1);
        rep(i,1,n){
            sci(p[i]);
            int u=p[i];
            dfn[u]=i;
            f=par[u];
            if(f)q[f].insert(P(i,sz[u]));
        }
        cnt=0;
        rep(i,1,n){
            if(q[i].empty())continue;
            int mn=(*q[i].begin()).fi;
            int mx=(*q[i].rbegin()).fi,w=(*q[i].rbegin()).se;
            if(dfn[i]!=mn-1 || mx<=dfn[i] || mx>dfn[i]+sz[i]-w)no[i]=1;
            else no[i]=0;
            cnt+=no[i];
        }
        while(Q--){
            sci(x);sci(y);
            int u=p[x],v=p[y];
            int fu=par[u],fv=par[v];
            if(fu)q[fu].erase(P(dfn[u],sz[u]));
            if(fv)q[fv].erase(P(dfn[v],sz[v]));
            swap(dfn[u],dfn[v]);
            swap(p[x],p[y]);
            if(fu)q[fu].insert(P(dfn[u],sz[u]));
            if(fv)q[fv].insert(P(dfn[v],sz[v]));
            rb(fu);rb(fv);rb(u);rb(v);
            //rep(i,1,n)printf("i:%d dfn:%d no:%d\n",i,dfn[i],no[i]);
            puts((cnt || p[1]!=1)?"NO":"YES");
            //dfn[u]=x;dfn[v]=y;

        }
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值