bzoj3123: [Sdoi2013]森林

题目链接

bzoj3123: [Sdoi2013]森林

题解

树上差分+主席树启发式合并

代码

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' || c > '9') 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 << 1]; 
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 cnt_node = 0; 
int ls[maxn * 20],rs[maxn * 20],cnt[maxn * 20]; 
void insert(int pre,int &now,int l,int r,int key) { 
    cnt[++ cnt_node] = cnt[now]; now = cnt_node; 
    ++ 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][22]; 
void dfs(int x) { 
    siz[x] = 1; 
    for(int i = 0;dad[x][i];++ i)dad[x][i + 1] = dad[dad[x][i]][i]; 
    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 = 18;i >= 0;i --) if(dep[dad[y][i]] >= dep[x]) y = dad[y][i]; 
    if(x == y) return x; 
    for(int i = 18;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); 
    //printf(" ************ %d\n",lca);
    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) { 
    int lca = LCA(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; 
    dfs(y); 
} 
void solve() { 
    num = 0,memset(head,0,sizeof head); 
    memset(root_num,0,sizeof root_num);memset(root,0,sizeof root); 
    memset(cnt,0,sizeof cnt); 
    cnt_node = MX = 0; 
    n = read(),m = read(); t = read(); 
    for(int i = 1;i <= n;++ i) val[i] = read(),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\n",lans = work_q(x,y,k)); 
        } else {
            int x = read() ^ lans,y = read() ^ lans; 
            if(siz[root_num[x]] < siz[root_num[y]]) std::swap(x,y); 
            work_L(x,y); 
        } 
    } 
} 
int main() { 
    //int testcase = read(); 
    //for(int i = 1;i <= testcase;++ i) solve();  
     
} 

posted @ 2018-08-10 07:16  zzzzx  阅读(157)  评论(0编辑  收藏  举报