ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

21.7.6 t3

2021-07-06 17:02:47  阅读:164  来源: 互联网

标签:21.7 int t3 son fa MAXN lca head


tag:虚树,重链剖分,交互,构造,二分


首先预处理一下以 \(1\) 为根,每个点到根的 \(dis\),然后用一次操作可以求出任意两点的 \(lca\),\(lca=dep_x\oplus dep_y\oplus query(x,y)\)。

可以考虑增量法,每次加入一个点,然后维护当前点集的虚树。

对于每次添加操作,首先对虚树重链剖分。

主要就是一个函数insert(chain,x),每次就调用insert(bel[1],x)

然后分为很多多多多多多多多多种情况。


首先求出链尾 \(lf\) 和 \(x\) 的 \(lca(y)\),对 \(y\) 分类讨论:

  • 如果 \(y=lf\),直接令 \(fa[x]=lf\)。
  • 否则如果 \(y\) 在虚树上,则找到 \(x\) 属于 \(y\) 的哪个轻儿子,然后往下递归。
  • 否则二分出 \(y\) 在这条链上的位置,然后直接插进去。

对于第二种情况,还要分类讨论。

首先可以用一次询问求出 \(sum=\bigoplus_{v\in son_{y}} lca(x,v)\)。

这个结果实际上是,若干个 \(y\) 和某个值 \(k\) 的异或和,因为 \(x\) 和其他轻儿子的 \(lca\) 一定是 \(y\)。

于是对奇偶性简单分讨一下可以求出 \(k\)。

设 \(v\) 为虚树上 \(y\) 在 \(x\) 那一侧的儿子。(这个可以通过二分用 \(log\) 次操作求出)

(注意有一种情况是 \(x\) 这一侧的点都还没有加入虚树,这时直接把 \(x\) 接在 \(y\) 下面即可。)

对于 \(k\) 分为几种情况:

  • \(k=x\),说明 \(x\) 是 \(v\) 的祖先,于是令 \(fa[x]=y,fa[v]=x\)。
  • \(k=v\),递归调用 insert(bel[v],x),这里不用求出 \(v\),直接看 \(k\) 是否出现过就行,所以复杂度不是 \(log^2\)。
  • \(k!=x,k!=v\),令 \(fa[k]=lca,fa[x]=fa[v]=k\)。

总之细节很多,调用次数是 \(O(nlogn)\),复杂度为 \(O(n^2logn)\)。

重链剖分是为了保证递归部分的复杂度。


代码照着上述过程写,唯一的细节可能就是二分了。。

多写几个函数就不太难写。

#include "hypercube.h"
#include<bits/stdc++.h>
using namespace std;

enum{
    MAXN = 3005
};

int n;

vector<int>to[MAXN];

int fa[MAXN], son[MAXN], leaf[MAXN], top[MAXN], sz[MAXN];
char vis[MAXN];
void dfs1(int x){
    sz[x] = 1; son[x] = 0;
    for(int v:to[x]){
        dfs1(v);
        sz[x] += sz[v];
        if(sz[v] > sz[son[x]]) son[x] = v;
    }
}

void dfs2(int x, int y){
    top[x] = y;
    if(son[x]) dfs2(son[x],y), leaf[x] = leaf[son[x]];
    else leaf[x] = x;
    for(int v:to[x]) if(v!=fa[x] and v!=son[x]) dfs2(v,v);
}

inline void rebuild(){
    for(int i=1; i<=n; i++) if(vis[i]) to[i].clear();
    for(int i=1; i<=n; i++) if(fa[i]) to[fa[i]].push_back(i);
    dfs1(1); dfs2(1,1);
}

int dep[MAXN];
inline int Query(int x, int y){
    static vector<int>tmp(1);
    tmp[0] = y; return query(x,tmp);
}

inline char check(int x, int pre, int y){
    static vector<int>tmp;
    tmp.clear();
    int res=0;
    for(int i=0; i<pre; i++) tmp.push_back(to[x][i]), res ^= dep[to[x][i]];
    res ^= query(y,tmp);
    if(pre&1) res ^= dep[y];
    if((res==0 and (~pre&1)) or (res==x and (pre&1))) return false;
    return true;
}

inline int Lca(int x, int y){return dep[x]^dep[y]^Query(x,y);}

void insert(int chaintop, int x){
    int lf = leaf[chaintop];
    int lca = (dep[lf]^dep[x]^Query(lf,x));
    if(lca==lf) return fa[x] = lf, void();
    // fprintf(stderr,"lca(%d %d) = %d\n",lf,x,lca);
    if(vis[lca]){
        int which = query(x,to[lca]);
        for(int v:to[lca]) which ^= dep[v];
        char odd = (int)to[lca].size()&1;
        if(odd) which ^= dep[x];
        if((which==0 and !odd) or (which==lca and odd)) return fa[x] = lca, void();
        if(!odd) which ^= lca;
        // fprintf(stderr,"which=%d\n",which);
        if(which!=x and vis[which]) return insert(which,x);

        int head=1, tail=to[lca].size();
        while(head<tail){
            int mid = head+tail >> 1;
            if(check(lca,mid,x)==false) head = mid+1;
            else tail = mid;
        }
        vis[which] = true;
        fa[which] = lca, fa[to[lca][head-1]] = which;
        if(which!=x) fa[x] = which;
        return;
    }

    if(x!=lca) fa[x] = lca, vis[lca] = true;
    static int chain[MAXN];
    int cnt=0;
    for(int i=lf; top[i]==chaintop; i=fa[i]) chain[++cnt] = i;
    int head=1, tail=cnt;
    while(head<tail){
        int mid = head+tail >> 1;
        if(Lca(chain[mid],lca)==lca) head = mid+1;
        else tail = mid;
    }
    fa[chain[head-1]] = lca;
    fa[lca] = chain[head];
}

void solve(int n, int Q, int data_type){
    for(int i=1; i<=n; i++) vis[i] = false, dep[i] = Query(1,i), fa[i] = 0; 
    ::n = n; vis[1] = true;
    for(int i=2; i<=n; i++) if(!vis[i]){
        rebuild();
        // fprintf(stderr,"insert %d\n",i);
        insert(1,i);
        vis[i] = true;
        // for(int j=1; j<=n; j++) if(vis[j]) fprintf(stderr,"(%d %d) ",j,fa[j]);cerr<<'\n';
    }
    for(int i=2; i<=n; i++) report(i,fa[i]);
}

标签:21.7,int,t3,son,fa,MAXN,lca,head
来源: https://www.cnblogs.com/oisdoaiu/p/14977722.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有