[SDOI2013]森林

题意:

强制在线

1.查询树上两点间权值第k小

2.连接两棵树

题解:

首先这题数据不得不吐槽

数据数字大小都是超过1e7的???

洛谷上又不能下载数据又只能显然re的 对拍了半天也没搞出来错(加上生成器还很难写)

查找第k大显然可以用主席树

而连接两棵树又是lct

考虑一下怎么搞,lct显然是不能用splay来维护区间k大的 只能放弃了

考虑用主席树维护每个点到根的路径

建树很简单

那么怎么合并呢

是可以用启发式合并暴力重构的(总共nlogn次插入,插入复杂度logn,总时间nlog2n)

那么考虑查询,平时在普通的主席树上查询是f(y)-f(x-1)

那么在树上就变成了f(x)+f(y)-2f(lca(x,y))再加上一下lca(x,y)

当然为了防止特判可以变成f(x)+f(y)-f(lca(x,y))-f(fa(lca(x,y))

求lca只需要在合并时暴力维护倍增数组就可以了(nlog2n)

所以总的时间复杂度是(nlog2n)

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxn 100000
#define INF 1000000000
struct re{
    int a,b;
}a[maxn*2];
struct ree{
    int h,t,x;
}p[20000000];
int bz[maxn][18],dep[maxn],root[maxn],v[maxn];
int l,now,head[maxn],count2[maxn],faa[maxn],n,m,t;
bool f[maxn];
void arr(int x,int y)
{
    a[++l].a=head[x];
    a[l].b=y;
    head[x]=l;
}
#define mid (h+t)/2
void insert(int &x,int y,int v,int h,int t)
{
    x=++now;
    p[x]=p[y]; p[x].x++;
    if (h==t) return; 
    if (mid>=v) insert(p[x].h,p[y].h,v,h,mid);
    else insert(p[x].t,p[y].t,v,mid+1,t);
}
void dfs(int x,int fa,int zx)
{
    insert(root[x],root[fa],v[x],1,INF); dep[x]=dep[fa]+1;
    f[x]=0; bz[x][0]=fa; count2[x]=1;
    faa[x]=zx;
    int u=head[x];
    while (u)
    {
        int v=a[u].b;
        if (v!=fa)
        { 
          dfs(v,x,zx);
          count2[x]+=count2[v];
        }
        u=a[u].a;
    }
}
void dfs2(int x,int fa,int zx)
{
       insert(root[x],root[fa],v[x],1,INF); faa[x]=zx; dep[x]=dep[fa]+1;
       bz[x][0]=fa;
       for (int i=1;i<=17;i++)
         bz[x][i]=bz[bz[x][i-1]][i-1];
       int u=head[x];
       while (u)
       {
        int v=a[u].b;
        if (v!=fa)
        {
            dfs2(v,x,zx);
        }
        u=a[u].a;
    }
} 
void merge(int x,int y)
{
    if (count2[faa[x]]<count2[faa[y]]) swap(x,y);
    count2[faa[x]]+=count2[faa[y]];
    dfs2(y,x,faa[x]);
}
int get_lca(int x,int y)
{
    if (dep[x]<dep[y]) swap(x,y);
    for (int i=17;i>=0;i--)
      if (dep[x]-(1<<i)>=dep[y]) x=bz[x][i];
    if (x==y) return(x);
    for (int i=17;i>=0;i--)
      if (bz[x][i]!=bz[y][i])
      {
          x=bz[x][i]; y=bz[y][i];
      }
    return(bz[x][0]);
}
int js(int x)
{
    return(p[p[x].h].x);
}
int query(int c,int d,int x,int y,int k,int h,int t)
{
    if (h==t) return(h);
    int tmp=js(x)+js(y)-js(c)-js(d);
    if (tmp<k) return (query(p[c].t,p[d].t,p[x].t,p[y].t,k-tmp,mid+1,t));
    else return (query(p[c].h,p[d].h,p[x].h,p[y].h,k,h,mid));
}
int main()
{
    freopen("noip.in","r",stdin);
    freopen("noip.out","w",stdout);
    int tmp;
    cin>>tmp;
    cin>>n>>m>>t;
    int c,d,e;
    for (int i=1;i<=n;i++) cin>>v[i];
    for (int i=1;i<=m;i++)
    {
        cin>>c>>d; arr(c,d); arr(d,c);
    }
    memset(f,1,sizeof(f));
    for (int i=1;i<=n;i++) if (f[i]) dfs(i,0,i);
    for (int i=1;i<=17;i++)
      for (int j=1;j<=n;j++)
        bz[j][i]=bz[bz[j][i-1]][i-1];
    int ans=0;
    char cc;
    for (int i=1;i<=t;i++)
    {
        cin>>cc;
        if (cc=='Q')
        {
            cin>>c>>d>>e;
            c=c^ans; d=d^ans; e=e^ans;
            int x=get_lca(c,d),y=bz[x][0];
            ans=query(root[x],root[y],root[c],root[d],e,1,INF);
            cout<<ans<<endl;
        } else
        {
            cin>>c>>d;
            c=c^ans; d=d^ans;
            merge(c,d);
            arr(c,d); arr(d,c);
          }
//          ans=0;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yinwuxiao/p/8496772.html