P3302 [SDOI2013]森林(主席树+倍增或LCT维护LCA)

P3302 [SDOI2013]森林(主席树+倍增或LCT维护LCA)

这道题要我们维护区间第K大,我们想到了主席树。

而这道题要我们动态维护加边,我们想到了 $LCT$ 。

对于树上的一条路径,我们可以使用差分的思想,设 $x$ 到 $y$ 的路径, $x$ 与 $y$ 的最近公共祖先为 $lca$ ,$A_i$ 表示从 $i$点到根结点维护的信息,那么我们可以利用 $A_x + A_y - A_{lca} - A_{fa_{lca}}$ 处理处$x$ 到 $y$ 的路径路径上的信息。

我们可以使用启发式合并来在线维护两个主席树的合并,和线段树合并差不多,将 $size$ 小的并向 $size$ 大的。

再考虑怎么维护 $lca$ ,我们考虑使用倍增求 $lca$ 那么我们需要做的是在每次主席树合并时更新倍增数组,我们只需在 $dfs$ 时稍作修改。

$update: $一定要写对启发式合并不要把 $fa[x]$ 与 $x$ 混淆。

  1 #include<bits/stdc++.h>
  2 #define MAXN 80001
  3 using namespace std;
  4 inline int read ()
  5 {
  6     int s=0,w=1;
  7     char ch=getchar ();
  8     while (ch<'0'||ch>'9'){if (ch=='-') w=-1;ch=getchar ();}
  9     while ('0'<=ch&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar ();
 10     return s*w;
 11 }
 12 struct edge{
 13     int v,nxt;
 14 }e[MAXN<<2];
 15 struct President_Tree{
 16     int l,r,size;
 17 }tr[MAXN*500];
 18 int testcase,n,m,t,Max,len,cnt,ans;
 19 int head[MAXN],a[MAXN],root[MAXN],fa[MAXN],size[MAXN];
 20 int mi[17],f[MAXN][17],dep[MAXN];
 21 vector<int>Vec;
 22 bool used[MAXN];
 23 inline void add (int u,int v)
 24 {
 25     e[++cnt].v=v,e[cnt].nxt=head[u],head[u]=cnt;
 26 }
 27 inline int find (int x)
 28 {
 29     if (fa[x]!=x) fa[x]=find (fa[x]);
 30     return fa[x];
 31 }
 32 inline void build (int &x,int l,int r)
 33 {
 34     tr[x=++len].size=0;
 35     if (l==r) return;
 36     int mid=(l+r)>>1;
 37     build (tr[x].l,l,mid);
 38     build (tr[x].r,mid+1,r);
 39 }
 40 inline void update (int &x,int y,int l,int r,int pos)
 41 {
 42     tr[x=++len]=tr[y];
 43     tr[x].size++;
 44     if (l==r) return;
 45     int mid=(l+r)>>1;
 46     if (pos<=mid) update (tr[x].l,tr[y].l,l,mid,pos);
 47     else update (tr[x].r,tr[y].r,mid+1,r,pos);
 48 }
 49 inline void dfs (int u,int ff,int rt)
 50 {
 51     fa[u]=ff;size[rt]++;
 52     used[u]=1,dep[u]=dep[ff]+1,f[u][0]=ff;
 53     for (int i=1;i<=16;i++) f[u][i]=f[f[u][i-1]][i-1];
 54     update (root[u],root[ff],1,Max,a[u]);
 55     for (register int i=head[u];i!=0;i=e[i].nxt)
 56         if (e[i].v!=ff)
 57             dfs (e[i].v,u,rt);
 58 }
 59 inline void merge (int x,int y)
 60 {
 61     int r1=find (x),r2=find (y);
 62     if (size[r1]<size[r2]) swap (x,y),swap (r1,r2);
 63     add (x,y),add (y,x);
 64     dfs (y,x,r1);
 65 }
 66 inline int LCA (int x,int y)
 67 {
 68     if (x==y) return x;
 69     if (dep[x]<dep[y]) swap (x,y);
 70     for (register int i=16;i>=0;i--)
 71         if (dep[f[x][i]]>=dep[y])
 72             x=f[x][i];
 73     if (x==y) return x;
 74     for (register int i=16;i>=0;i--)
 75         if (f[x][i]!=f[y][i])
 76             x=f[x][i],y=f[y][i];
 77     return f[x][0];
 78 }
 79 inline int query (int x,int y,int pre1,int pre2,int l,int r,int k)
 80 {
 81     if (l==r) return Vec[l-1];
 82     int lsize=tr[tr[x].l].size+tr[tr[y].l].size-tr[tr[pre1].l].size-tr[tr[pre2].l].size;
 83     int mid=(l+r)>>1;
 84     if (k<=lsize) return query (tr[x].l,tr[y].l,tr[pre1].l,tr[pre2].l,l,mid,k);
 85     else return query (tr[x].r,tr[y].r,tr[pre1].r,tr[pre2].r,mid+1,r,k-lsize);
 86 }
 87 int main()
 88 {
 89     mi[0]=1;for (register int i=1;i<=16;i++) mi[i]=mi[i-1]<<1;
 90     testcase=read ();
 91     n=read (),m=read (),t=read ();
 92     for (register int i=1;i<=n;i++) fa[i]=i;
 93     for (register int i=1;i<=n;i++) a[i]=read (),Vec.push_back (a[i]);
 94     sort (Vec.begin (),Vec.end ());
 95     Vec.erase (unique (Vec.begin (),Vec.end ()),Vec.end ());
 96     for (register int i=1;i<=n;i++)
 97         a[i]=lower_bound (Vec.begin (),Vec.end (),a[i])-Vec.begin ()+1;
 98     Max=Vec.size ();
 99     for (register int i=1;i<=m;i++)
100     {
101         int u=read (),v=read ();
102         add (u,v),add (v,u);
103     }
104     build (root[0],1,Max);
105     for (register int i=1;i<=n;i++)
106         if (!used[i])
107             dfs (i,0,i);
108     while (t--)
109     {
110         char ch=getchar ();
111         while (ch!='L'&&ch!='Q') ch=getchar ();
112         int x=read ()^ans,y=read ()^ans;
113         if (ch=='L') merge (x,y);
114         else
115         {
116             int k=read ()^ans,lca=LCA (x,y);
117             ans=query (root[x],root[y],root[lca],root[f[lca][0]],1,Max,k);
118             printf ("%d
",ans);
119         }
120     }
121     return 0;
122 }

还有第二个思路,我们可以使用 $LCT$ 来维护 $LCA$,这里还没写,下次再补

原文地址:https://www.cnblogs.com/PaulShi/p/10098999.html