[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\n",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 }

 

posted @ 2017-08-02 20:05  LadyLex  阅读(755)  评论(0编辑  收藏  举报