其他分享
首页 > 其他分享> > (多校)超级加倍

(多校)超级加倍

作者:互联网

第一次考场见重构树

我们按点从小到大依次插入

不太好描述,先上码:

for(re int i=2;i<=n;i++) {
        for(re int j=0;j<vec[i].size();j++) {
            int to=vec[i][j]; if(to<i) { add(i,find(to)); fa[find(to)]=i; }
        }
    }

那么一个点到他重构树的子树内的点的路径最大值一定为该点

我们再反过来建一次树:

for(re int i=n-1;i>=1;i--) {
        for(re int j=0;j<vec[i].size();j++) {
            int to=vec[i][j]; if(to>i) { add(i,find(to)); fa[find(to)]=i; }
        }
    }

那一个点到他重构树的子树内的点的路径最小值一定为该点

则若 \((i,j)\) 满足条件,那么在两棵重构树内两点肯定互为祖先

此题完结

Code
#include <bits/stdc++.h>
#define re register
// #define int long long
#define ll long long
#define pir make_pair
#define fr first 
#define sc second
#define db double
#define pb push_back
using namespace std;
const int mol=998244353;
const int maxn=2e6+10;
const int INF=1e9+10;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return ans; }
inline int read() {
    int s=0,w=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); }
    return s*w;
}

int n,tot,fa[maxn],dfn[maxn],size[maxn]; ll ans;
struct EDGE { int var,nxt; } edge[maxn<<1];
int head[maxn],cnt;
inline void add(int a,int b) { edge[++cnt]=(EDGE){ b,head[a] }; head[a]=cnt; }
inline int find(int a) { return a==fa[a]? a:fa[a]=find(fa[a]); }
namespace STG {
    int ary[maxn];
    #define lew(x) x&-x
    inline void ins(int pos,int val) { while(pos<=n) { ary[pos]+=val; pos+=lew(pos); } }
    inline ll quy(int pos) { ll ans=0; while(pos) { ans+=ary[pos]; pos-=lew(pos); } return ans; }
}
vector<int>vec[maxn];
inline void clear() { for(re int i=1;i<=n;i++) fa[i]=i,head[i]=-1; cnt=0; }
inline void dfs1(int now) {
    dfn[now]=++tot; size[now]=1;
    for(re int i=head[now];~i;i=edge[i].nxt) {
        int to=edge[i].var; dfs1(to); size[now]+=size[to];
    }
}
inline void dfs2(int now) {
    ans+=STG::quy(dfn[now]+size[now]-1)-STG::quy(dfn[now]-1);
    STG::ins(dfn[now],1);
    for(re int i=head[now];~i;i=edge[i].nxt) {
        int to=edge[i].var; dfs2(to);
    }
    STG::ins(dfn[now],-1);
}
signed main(void) {
    freopen("charity.in","r",stdin); freopen("charity.out","w",stdout);
    n=read();
    for(re int i=1,x;i<=n;i++) { x=read(); vec[x].pb(i); vec[i].pb(x); }
    clear();
    for(re int i=2;i<=n;i++) {
        for(re int j=0;j<vec[i].size();j++) {
            int to=vec[i][j]; if(to<i) { add(i,find(to)); fa[find(to)]=i; }
        }
    }
    dfs1(n);
    clear();
    for(re int i=n-1;i>=1;i--) {
        for(re int j=0;j<vec[i].size();j++) {
            int to=vec[i][j]; if(to>i) { add(i,find(to)); fa[find(to)]=i; }
        }
    }
    dfs2(1);
    printf("%lld\n",ans);
}

标签:ch,int,超级,多校,long,加倍,re,ans,define
来源: https://www.cnblogs.com/zjxlm/p/15535170.html