zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    494. Target Sum 添加标点符号求和
    636. Exclusive Time of Functions 进程的执行时间
    714. Best Time to Buy and Sell Stock with Transaction Fee有交易费的买卖股票
    377. Combination Sum IV 返回符合目标和的组数
    325. Maximum Size Subarray Sum Equals k 和等于k的最长子数组
    275. H-Index II 递增排序后的论文引用量
    274. H-Index论文引用量
    RabbitMQ学习之HelloWorld(1)
    java之struts2的数据处理
    java之struts2的action的创建方式
  • 原文地址:https://www.cnblogs.com/refun/p/10083588.html
Copyright © 2011-2022 走看看