• [BZOJ3123][Sdoi2013]森林 主席树+启发式合并


    3123: [Sdoi2013]森林

    Time Limit: 20 Sec  Memory Limit: 512 MB

    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。之后的操作类似。 

     

    题解:

    看到求k值,我们很容易想到主席树这种求区间k大值的工具(不了解树上主席树的同学可以看一下我之前的讲解http://www.cnblogs.com/LadyLex/p/7275164.html,再参考一下下面的代码)

    但是,本题的合并操作给我们带来了麻烦,让我们无处下手。难道我们之间暴力添加吗?肯定会T。

    所以我们考虑利用启发式合并,即把个数较小的树插入个数较大的树中。

    启发式合并的操作听起来和暴力没有什么区别,但是它的复杂度是有保障的:

    每次合并,新树的大小是原来较小树大小的二倍以上,因此最多需要logn次合并成了1棵树。

    每次合并平均是(n/2)log权值的,因此总时间复杂度是O(nlognlog权值)的

    如果离散化的话,跑的就更快了,大约O(nlog2n)(不过我自己的代码没有离散,233)

    代码见下:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <vector>
     4 #include <algorithm>
     5 using namespace std;
     6 const int N=80800,MAXN=1000000000;
     7 int n,cnt,val[N],sum,adj[N],e;
     8 int origin[N],belong[N],size[N],deep[N];
     9 struct edge{int zhong,next;}s[N<<1];
    10 inline void swap(int &a,int &b){int t=a;a=b;b=t;}
    11 inline void add(int qi,int zhong){s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
    12 int f[N][25],bin[25];
    13 inline void mission1(int x)
    14     {for(int i=1;i<=20;i++)f[x][i]=f[f[x][i-1]][i-1];}
    15 inline int LCA(int a,int b)
    16 {
    17     if(deep[a]<deep[b])swap(a,b);
    18     int cha=deep[a]-deep[b];
    19     for(int j=20;~j;j--)if(cha&bin[j])a=f[a][j];
    20     if(a==b)return a;
    21     for(int j=20;~j;j--)
    22         if(f[a][j]!=f[b][j])a=f[a][j],b=f[b][j];
    23     return f[a][0];
    24 }
    25 struct node
    26 {
    27     int cnt;node *ch[2];
    28     node(){cnt=0;ch[0]=ch[1]=NULL;}
    29     inline void update(){cnt=ch[0]->cnt+ch[1]->cnt;}
    30 }*null=new node(),*root[N];
    31 inline node* newnode()
    32 {
    33     node *o=new node();
    34     o->ch[0]=o->ch[1]=null;
    35     return o;
    36 }
    37 inline int query(int x,int y,int k)
    38 {
    39     int lca=LCA(x,y),t=f[lca][0],l=1,r=MAXN;
    40     node *a=root[x],*b=root[y],*c=root[lca],*d=root[t];
    41     while(l<r)
    42     {
    43         int tmp=a->ch[0]->cnt+b->ch[0]->cnt-c->ch[0]->cnt-d->ch[0]->cnt,mi=(l+r)>>1;
    44         if(tmp>=k)a=a->ch[0],b=b->ch[0],c=c->ch[0],d=d->ch[0],r=mi;
    45         else k-=tmp,a=a->ch[1],b=b->ch[1],c=c->ch[1],d=d->ch[1],l=mi+1;
    46     }
    47     return r;
    48 }
    49 void insert(node *&a,node *b,int l,int r,int pos)
    50 {
    51     a->cnt=b->cnt+1;
    52     int mi=(l+r)>>1;
    53     if(l==r)return;
    54     if(pos<=mi)a->ch[1]=b->ch[1],a->ch[0]=newnode(),insert(a->ch[0],b->ch[0],l,mi,pos);
    55     else a->ch[0]=b->ch[0],a->ch[1]=newnode(),insert(a->ch[1],b->ch[1],mi+1,r,pos);
    56     a->update();
    57 }
    58 void dfs1(int rt,int fa)
    59 {
    60     f[rt][0]=fa;mission1(rt);
    61     sum++;deep[rt]=deep[fa]+1;belong[rt]=cnt;
    62     insert(root[rt],root[fa],1,MAXN,val[rt]);
    63     for(int i=adj[rt];i;i=s[i].next)
    64         if(s[i].zhong!=fa)dfs1(s[i].zhong,rt);
    65 }
    66 void dfs2(int rt,int fa,int anc)
    67 {
    68     f[rt][0]=fa;deep[rt]=deep[fa]+1;mission1(rt);belong[rt]=anc;
    69     insert(root[rt],root[fa],1,MAXN,val[rt]);
    70     for(int i=adj[rt];i;i=s[i].next)
    71         if(s[i].zhong!=fa)dfs2(s[i].zhong,rt,anc);
    72 }
    73 int main()
    74 {
    75     null->ch[0]=null->ch[1]=null;
    76     bin[0]=1;for(int i=1;i<=22;i++)bin[i]=bin[i-1]<<1;
    77     int ans=0,m,t,a,b,d;char c[3];scanf("%d",&t);
    78     scanf("%d%d%d",&n,&m,&t);
    79     for(int i=0;i<=n;i++)root[i]=newnode();
    80     for(int i=1;i<=n;i++)scanf("%d",&val[i]);
    81     while(m--)scanf("%d%d",&a,&b),add(a,b),add(b,a);
    82     for(int i=1;i<=n;i++)
    83         if(!belong[i])sum=0,cnt++,dfs1(i,0),origin[cnt]=i,size[cnt]=sum;
    84     while(t--)
    85     {
    86         scanf("%s%d%d",c,&a,&b);a^=ans,b^=ans;
    87         if(c[0]=='Q')scanf("%d",&d),d^=ans,printf("%d
    ",ans=query(a,b,d));
    88         else 
    89         {
    90             add(a,b),add(b,a);
    91             if(size[belong[a]]>size[belong[b]])
    92                 size[belong[a]]+=size[belong[b]],dfs2(b,a,belong[a]);
    93             else size[belong[b]]+=size[belong[a]],dfs2(a,b,belong[b]);
    94         }
    95     }
    96 }
  • 相关阅读:
    第六周学习心得
    syncnavigator关于win10、win8系统无法注册机进行激活的问题
    使用SyncNavigator轻松实现数据库异地同步、断点续传、异构同步
    数据库同步的正确打开方式
    使用SyncNavigator实现数据库异地同步。
    聊聊MySQL主从数据库同步的那些事儿
    高并发架构系列:数据库主从同步的3种一致性方案实现,及优劣比较
    MySQL binlog数据库同步技术总结
    数据库同步的两种方式
    某省肿瘤医院 — 数据备份 + 数据库同步
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7275793.html
Copyright © 2020-2023  润新知