• BZOJ3123:[SDOI2013]森林(主席树,启发式合并)


    Description

    Input

    第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
    第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
     接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

    Output

    对于每一个第一类操作,输出一个非负整数表示答案。

    Sample Input

    1
    8 4 8
    1 1 2 2 3 3 4 4
    4 7
    1 8
    2 4
    2 1
    Q 8 7 3 Q 3 5 1
    Q 10 0 0
    L 5 4
    L 3 2 L 0 7
    Q 9 2 5 Q 6 1 6

    Sample Output

    2
    2
    1
    4
    2

    HINT

    对于第一个操作 Q 8 7 3,此时 lastans=0,所以真实操作为Q 8^0 7^0 3^0,也即Q 8 7 3。点8到点7的路径上一共有5个点,其权值为4 1 1 2 4。这些权值中,第三小的为 2,输出 2,lastans变为2。对于第二个操作 Q 3 5 1 ,此时lastans=2,所以真实操作为Q 3^2 5^2 1^2 ,也即Q 1 7 3。点1到点7的路径上一共有4个点,其权值为 1 1 2 4 。这些权值中,第三小的为2,输出2,lastans变为 2。之后的操作类似。

    Solution

    可以发现没有连边那个操作就是裸的把主席树放到树上跑……QAQ 具体操作可以看我这篇博客

    然后又发现只有连边没有删边……那么就可以直接每次连边就启发式合并两棵树,对小的那颗暴力全部重建主席树。复杂度$nlog^2n$

    Code

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<algorithm>
      5 #define N (80009)
      6 using namespace std;
      7 
      8 struct Sgt{int ls,rs,val;}Segt[N<<7];
      9 struct Edge{int to,next;}edge[N<<1];
     10 int head[N],num_edge;
     11 int testcase,n,m,q,u,v,num,x,y,k,lca,sgt_num,lastans;
     12 int Root[N],a[N],b[N],Depth[N],f[N][18],vis[N],Top[N],Size[N];
     13 char opt[2];
     14 
     15 int getid(int x) {return lower_bound(b+1,b+n+1,x)-b;}
     16 
     17 void add(int u,int v)
     18 {
     19     edge[++num_edge].to=v;
     20     edge[num_edge].next=head[u];
     21     head[u]=num_edge;
     22 }
     23 
     24 int Update(int pre,int l,int r,int x)
     25 {
     26     int now=++sgt_num;
     27     Segt[now].val=Segt[pre].val+1;
     28     Segt[now].ls=Segt[pre].ls;
     29     Segt[now].rs=Segt[pre].rs;
     30     if (l==r) return now;
     31     int mid=(l+r)>>1;
     32     if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x);
     33     else Segt[now].rs=Update(Segt[now].rs,mid+1,r,x);
     34     return now;
     35 }
     36 
     37 int Build(int l,int r)
     38 {
     39     int now=++sgt_num;
     40     if (l==r) return now;
     41     int mid=(l+r)>>1;
     42     Segt[now].ls=Build(l,mid);
     43     Segt[now].rs=Build(mid+1,r);
     44     return now;
     45 }
     46 
     47 void DFS(int x,int fa,int top)
     48 {
     49     Size[top]++; Depth[x]=Depth[fa]+1;
     50     f[x][0]=fa; Top[x]=top; vis[x]=true;
     51     for (int i=1; i<=17; ++i)
     52         f[x][i]=f[f[x][i-1]][i-1];
     53     int id=getid(a[x]);
     54     Root[x]=Update(Root[fa],1,num,id);
     55     for (int i=head[x]; i; i=edge[i].next)
     56         if (edge[i].to!=fa)
     57         {
     58             DFS(edge[i].to,x,top);
     59             Size[x]+=Size[edge[i].to];
     60         }
     61 }
     62 
     63 int LCA(int x,int y)
     64 {
     65     if (Depth[x]<Depth[y]) swap(x,y);
     66     for (int i=17; i>=0; --i)
     67         if (Depth[f[x][i]]>=Depth[y]) x=f[x][i];
     68     if (x==y) return x;
     69     for (int i=17; i>=0; --i)
     70         if (f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i];
     71     return f[x][0];
     72 }
     73 
     74 int Query(int u,int v,int lca,int flca,int l,int r,int k)
     75 {
     76     if (l==r) return b[l];
     77     int mid=(l+r)>>1;
     78     int x=Segt[Segt[u].ls].val+Segt[Segt[v].ls].val-Segt[Segt[lca].ls].val-Segt[Segt[flca].ls].val;
     79     if (k<=x) return Query(Segt[u].ls,Segt[v].ls,Segt[lca].ls,Segt[flca].ls,l,mid,k);
     80     else return Query(Segt[u].rs,Segt[v].rs,Segt[lca].rs,Segt[flca].rs,mid+1,r,k-x);
     81 }
     82 
     83 int main()
     84 {
     85     scanf("%d",&testcase);
     86     scanf("%d%d%d",&n,&m,&q);
     87     for (int i=1; i<=n; ++i)
     88         scanf("%d",&a[i]), b[i]=a[i];
     89     sort(b+1,b+n+1);
     90     num=unique(b+1,b+n+1)-b-1;
     91     Root[0]=Build(1,num);
     92     for (int i=1; i<=m; ++i)
     93     {
     94         scanf("%d%d",&u,&v);
     95         add(u,v); add(v,u);
     96     }
     97     for (int i=1; i<=n; ++i)
     98         if (!vis[i]) DFS(i,0,i);
     99     for (int Q=1; Q<=q; ++Q)
    100     {
    101         scanf("%s",opt);
    102         if (opt[0]=='Q')
    103         {
    104             scanf("%d%d%d",&x,&y,&k);
    105             x^=lastans; y^=lastans; k^=lastans;
    106             int lca=LCA(x,y);
    107             int ans=Query(Root[x],Root[y],Root[lca],Root[f[lca][0]],1,num,k);
    108             printf("%d
    ",ans); lastans=ans;
    109         }
    110         else
    111         {
    112             scanf("%d%d",&x,&y);
    113             x^=lastans; y^=lastans;
    114             add(x,y); add(y,x);
    115             if (Size[Top[x]]<Size[Top[y]]) DFS(x,y,Top[y]);
    116             else DFS(y,x,Top[x]);
    117         }
    118     }
    119 }
  • 相关阅读:
    一台机器同时启动两个tomcat
    JSP ie8 ie9下标准文档变为杂项模式(Quirks)的解决办法
    mysql备份远程数据库到本地(转载)
    java 读取properties文件
    java中使用MD5进行加密(转)
    Java中继承thread类与实现Runnable接口的区别(转)
    19-background
    18-超链接导航栏案例
    17-文本属性和字体属性
    16-margin的用法
  • 原文地址:https://www.cnblogs.com/refun/p/10083588.html
Copyright © 2020-2023  润新知