• 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$,这里还没写,下次再补

  • 相关阅读:
    团队建设
    风云变幻六十年 平板电脑演变史回顾
    在线ide汇总
    XAMPP中启动tomcat报错的解决方法
    ExtJs 中 xtype 与组件类的对应表
    FineReport关于Linux下字体乱码终极解决方案
    SqlDataReader的关闭问题
    MemberShip学习之:注册用户
    索引超出范围。必须为非负值并小于集合大小。
    利用SiteMapPath控件做论坛导航(也适合其它系统)
  • 原文地址:https://www.cnblogs.com/PaulShi/p/10098999.html
Copyright © 2020-2023  润新知