luoguP3302 [SDOI2013]森林 主席树 启发式合并

题目链接

luoguP3302 [SDOI2013]森林

题解

本来这题树上主席树暴力启发式合并就完了
结果把lca写错了...
以后再也不这么写了
复杂度(O(nlog^2n))

"for(int i = 0;dad[x][i];++ i) dad[x][i+1] = dad[dad[x][i]][i]"

De了两个多小时....QAQ

代码

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
  
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar(); } 
    while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
} 
  
const int maxn = 100007; 
struct NNnode {
    int v,next; 
} edge[maxn << 2]; 
int num = 0,head[maxn]; 
inline void add_edge(int u,int v)  { 
    edge[++ num].v = v; edge[num].next = head[u]; head[u] = num; 
} 
  
int root[maxn],val[maxn],n,m,t,MX; 
int tot = 0; 
int ls[40000000],rs[40000000],cnt[40000000]; 
void insert(int pre,int &now,int l,int r,int key) { 
    cnt[++ tot] = cnt[now]; now = tot; 
    ++ cnt[now]; 
    if(l == r) return ; 
    int mid = l + r >> 1; 
    ls[now] = ls[pre]; rs[now] = rs[pre]; 
    if(key <= mid) insert(ls[pre],ls[now],l,mid,key); 
    else insert(rs[pre],rs[now],mid + 1,r,key);  
} 
  
int query(int t1,int t2,int t3,int t4,int l,int r,int k) { 
    if (l == r) return l; 
    int mid = l + r >> 1; 
    int dtl = cnt[ls[t1]] + cnt[ls[t2]] - cnt[ls[t3]] - cnt[ls[t4]]; 
    if(k <= dtl) return query(ls[t1],ls[t2],ls[t3],ls[t4],l,mid,k); 
    else return query(rs[t1],rs[t2],rs[t3],rs[t4],mid + 1,r,k - dtl);  
} 
  
int root_num[maxn],siz[maxn], dep[maxn],dad[maxn][25]; 
void dfs(int x) { 
    siz[x] = 1; 
    for(int i = 1;i < 20;++i) 
      dad[x][i] = dad[dad[x][i - 1]][i - 1]; 
    insert(root[dad[x][0]],root[x],1,MX,val[x]); 
    for(int i = head[x];i;i = edge[i].next) { 
        int v = edge[i].v; 
        if(v == dad[x][0]) continue; 
        root_num[v] = root_num[x]; 
        dad[v][0] = x; dep[v] = dep[x] + 1; 
        dfs(v); 
        siz[x] += siz[v]; 
    } 
} 
int LCA(int x,int y) { 
      
    if(dep[x] > dep[y]) std::swap(x,y); 
    for(int i = 19;i >= 0;i --) if(dep[dad[y][i]] >= dep[x]) y = dad[y][i]; 
    if(x == y) return x; 
    for(int i = 19;i >= 0;i --) if(dad[y][i] != dad[x][i]) y = dad[y][i],x = dad[x][i]; 
    return dad[x][0]; 
} 
int work_q(int x,int y,int k) { 
    int lca = LCA(x,y); 
    int F_lca = dad[lca][0]; 
    return query(root[x],root[y],root[lca],root[dad[lca][0]],1,MX,k); 
} 
void work_L(int x,int y) { 
    //printf("%d ***** %d
",x,y); 
    if(siz[root_num[x]] < siz[root_num[y]]) std::swap(x,y); 
    dad[y][0] = x; 
    siz[root_num[x]] += siz[root_num[y]]; 
    root_num[y] = root_num[x]; 
    dep[y] = dep[x] + 1; add_edge(x,y);add_edge(y,x);  
    dfs(y); 
} 
int b[maxn]; 
void solve() { 
    tot = MX = 0; 
    n = read(),m = read(); t = read(); 
    for(int i = 1;i <= n;++ i) b[i] = val[i] = read(),MX = std::max(val[i],MX); 
    std::sort(b + 1,b + n + 1); 
    int len = std::unique(b + 1,b + n + 1) - b - 1; 
    for(int i = 1;i <= n;++ i) val[i] = std::lower_bound(b + 1,b + len + 1,val[i]) - b,MX = std::max(val[i],MX);
      
    for(int x,y,i = 1;i <= m;++ i) { 
        x = read(), y = read(); 
        add_edge(x,y) , add_edge(y,x);  
    } 
    for(int i = 1;i <= n;++ i) 
        if(!root_num[i]) root_num[i] = i,dep[i] = 1,dfs(i); 
    char opt[20]; 
    int lans = 0; 
    while(t --) { 
        scanf("%s",opt + 1) ; 
        if(opt[1] == 'Q')  { 
            int x = read() ^ lans,y = read() ^ lans, k = read() ^ lans; 
            //printf("%d **** %d *** %d *** &&&
",x,y,lans); 
            printf("%d
",lans = b[work_q(x,y,k)]); 
        } else { 
            int x = read() ,y = read() ; 
            x ^= lans,y ^= lans; 
            //printf("%d **** %d *** %d *** ***
",x,y,lans); 
            work_L(x,y); 
        } 
    } 
} 
int main() { 
    int testcase = read(); //whattttt the fucccck? 
    testcase = 1;  
    for(int i = 1;i <= testcase;++ i) solve();  
      
} 
原文地址:https://www.cnblogs.com/sssy/p/9637228.html