区间(树上)第k小(大)问题

 

P3834 【模板】可持久化线段树 1(主席树) 

        静态区间第k小。

        主席树模板题
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,x,y,k;
 4 struct node 
 5 {
 6     int l,r,sum;
 7 }num[3400000];
 8 int head[200050],a[200050],v[200050],pos[200050],w[200050],cnt,tot;
 9 bool cmp(int x,int y)
10 {
11     return a[x]<a[y];
12 }
13 void build(int l,int r,int &u)
14 {
15     u=++tot;
16     num[u].sum=0;
17     if(l==r)
18         return ;
19     int mid=(l+r)>>1;
20     build(l,mid,num[u].l);
21     build(mid+1,r,num[u].r);
22 }
23 void update(int l,int r,int val,int las,int &u)
24 {
25     u=++tot;
26     num[u].l=num[las].l;
27     num[u].r=num[las].r;
28     num[u].sum=num[las].sum+1;
29     if(l==r)
30         return ;
31     int mid=(l+r)>>1;
32     if(val<=mid)
33         update(l,mid,val,num[las].l,num[u].l);
34     else
35         update(mid+1,r,val,num[las].r,num[u].r);
36 }
37 int calc(int l,int r,int las,int u,int tk)
38 {
39     if(l==r)
40         return l;
41     int mid=(l+r)>>1;
42     int tmp=num[num[u].l].sum-num[num[las].l].sum;
43     if(tmp>=tk)
44         return calc(l,mid,num[las].l,num[u].l,tk);
45     else
46         return calc(mid+1,r,num[las].r,num[u].r,tk-tmp);
47 }
48 int main()
49 {
50     scanf("%d%d",&n,&m);
51     for(int i=1;i<=n;i++)
52     {
53         scanf("%d",&a[i]);
54         pos[i]=i;
55     }
56     sort(pos+1,pos+n+1,cmp);
57     for(int i=1;i<=n;i++)
58     {
59         if(a[pos[i]]!=a[pos[i-1]]||i==1)
60             w[++cnt]=a[pos[i]];
61         v[pos[i]]=cnt;
62     }
63     build(1,cnt,head[0]);
64     for(int i=1;i<=n;i++)
65         update(1,cnt,v[i],head[i-1],head[i]);
66     while(m--)
67     {
68         scanf("%d%d%d",&x,&y,&k);
69         printf("%d\n",w[calc(1,cnt,head[x-1],head[y],k)]);
70     }
71     return 0;
72 }
静态区间第k小

        离线的区间第k小当然也可以套整体二分。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,tot,cnt;
 4 int ans[200050],c[200050],L=1e9,R=-1e9;
 5 int pos[200050],lis[200050];
 6 void calc_add(int u,int v)
 7 {
 8     while(u<=n)
 9     {
10         c[u]+=v;
11         u+=u&-u;
12     }
13 }
14 int calc_ask(int u)
15 {
16     int sum=0;
17     while(u)
18     {
19         sum+=c[u];
20         u-=u&-u;
21     }
22     return sum;
23 }
24 struct node
25 {
26     int opt,x,l,r,val;
27 }t[400050],tl[400050],tr[400050];
28 bool cmp (int a,int b)
29 {
30     return t[a].val<t[b].val;
31 }
32 void calc(int l,int r,int x,int y)
33 {
34     if(x==y)
35     {
36         for(int i=l;i<=r;++i)
37             if(t[i].opt)
38                 ans[t[i].x]=lis[x];
39         return ;
40     }
41     int mid=(x+y)>>1;
42     int totl=0,totr=0;
43     for(int i=l;i<=r;++i)
44     {
45         if(!t[i].opt)
46         {
47             if(t[i].val<=mid)
48             {
49                 calc_add(t[i].x,1);
50                 tl[++totl]=t[i];
51             }
52             else
53                 tr[++totr]=t[i];
54         }
55         else
56         {
57             int tmp=calc_ask(t[i].r)-calc_ask(t[i].l-1);
58             if(tmp>=t[i].val)
59                 tl[++totl]=t[i];
60             else
61             {
62                 t[i].val-=tmp;
63                 tr[++totr]=t[i];
64             }
65         }
66     }
67     for(int i=1;i<=totl;++i)
68         if(!tl[i].opt)
69             calc_add(tl[i].x,-1);
70     for(int i=1;i<=totl;++i)    t[l+i-1]=tl[i];
71     for(int i=1;i<=totr;++i)    t[l+totl+i-1]=tr[i];
72     calc(l,l+totl-1,x,mid);
73     calc(l+totl,r,mid+1,y);
74 }
75 int main()
76 {
77     scanf("%d%d",&n,&m);tot=n;
78     for(int i=1;i<=tot;++i)
79     {
80         scanf("%d",&t[i].val);
81         t[i].x=i;    pos[i]=i;
82     }tot=n+m;
83     sort(pos+1,pos+n+1,cmp);
84     for(int i=1;i<=n;++i)
85     {
86         lis[i]=t[pos[i]].val;
87         t[pos[i]].val=i;
88     }
89     for(int i=n+1;i<=tot;++i)
90     {
91         scanf("%d%d%d",&t[i].l,&t[i].r,&t[i].val);
92         t[i].x=i-n; t[i].opt=1;
93     }
94     calc(1,tot,1,n);
95     for(int i=1;i<=m;++i)
96         printf("%d\n",ans[i]);
97     return 0;
98 }
整体二分

 


P2633 Count on a tree

        静态树上路径第k小。

        沿用静态区间第k小的做法,每个节点用一棵线段树维护从根节点到当前节点路径中的节点权值。

查询时只要找到 lca 就可以变成两条深度递增的链了。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int n,m,x,y,ans,tot;
  4 int cnt,k;
  5 int w[100050],lca;
  6 int val[100050];
  7 int pos[100050];
  8 int rnk[100050];
  9 int head[200050];
 10 int son[2000050][2];
 11 int root[100050];
 12 int sum[2000050];
 13 int fath[100050];
 14 int nex[200050],ver[200050];
 15 int f[100050][20],deep[100050];
 16 bool cmp(int x,int y)
 17 {
 18     return val[x]<val[y];
 19 }
 20 void calc_build(int l,int r,int val,int u,int &v)
 21 {
 22     v=++cnt;
 23     sum[v]=sum[u]+1;
 24     if(l==r)
 25         return ;
 26     son[v][0]=son[u][0];
 27     son[v][1]=son[u][1];
 28     int mid=(l+r)>>1;
 29     if(val<=mid)
 30         calc_build(l,mid,val,son[u][0],son[v][0]);
 31     else
 32         calc_build(mid+1,r,val,son[u][1],son[v][1]);
 33 }
 34 int calc_ask(int l,int r,int a,int b,int c,int d)
 35 {
 36     if(l==r)
 37         return l;
 38     int mid=(l+r)>>1;
 39     int tmp=sum[son[a][0]]+sum[son[b][0]]-sum[son[c][0]]-sum[son[d][0]];
 40     if(tmp>=k)
 41         return calc_ask(l,mid,son[a][0],son[b][0],son[c][0],son[d][0]);
 42     k-=tmp;
 43     return calc_ask(mid+1,r,son[a][1],son[b][1],son[c][1],son[d][1]);
 44 }
 45 void add(int x,int y)
 46 {
 47     nex[++tot]=head[x];
 48     head[x]=tot;
 49     ver[tot]=y;
 50 }
 51 void dfs(int u,int fa)
 52 {
 53     calc_build(1,n,rnk[u],root[fa],root[u]);
 54     fath[u]=fa;
 55     deep[u]=deep[fa]+1;f[u][0]=fa;
 56     for(int k=1;k<=18;++k)
 57         f[u][k]=f[f[u][k-1]][k-1];
 58     for(int i=head[u];i;i=nex[i])
 59         if(ver[i]!=fa)
 60             dfs(ver[i],u);
 61 }
 62 int calc_lca(int a,int b)
 63 {
 64     if(deep[a]<deep[b])
 65         swap(a,b);
 66     for(int i=18;i>=0;--i)
 67         if(deep[f[a][i]]>=deep[b])
 68             a=f[a][i];
 69     if(a==b)
 70         return a;
 71     for(int i=18;i>=0;--i)
 72         if(f[a][i]!=f[b][i])
 73         {
 74             a=f[a][i];
 75             b=f[b][i];
 76         }
 77     return f[a][0];
 78 }
 79 int main()
 80 {
 81     scanf("%d%d",&n,&m);
 82     for(int i=1;i<=n;++i)
 83     {
 84         scanf("%d",&val[i]);
 85         pos[i]=i;
 86     }
 87     sort(pos+1,pos+n+1,cmp);
 88     for(int i=1;i<=n;++i)
 89     {
 90         rnk[pos[i]]=i;
 91         w[i]=val[pos[i]];
 92     }
 93     for(int i=1;i<n;++i)
 94     {
 95         scanf("%d%d",&x,&y);
 96         add(x,y);    add(y,x);
 97     }
 98     dfs(1,0);
 99     while(m--)
100     {
101         scanf("%d%d%d",&x,&y,&k);
102         x^=ans;
103         lca=calc_lca(x,y);
104         ans=calc_ask(1,n,root[x],root[y],root[lca],root[fath[lca]]);
105         ans=w[ans];
106         printf("%d\n",ans);
107     }
108     return 0;
109 }
静态树上路径第k小

 


P3380 【模板】二逼平衡树(树套树)

        动态区间第k小。

        这次是树套树的模板了。树状数组套权值线段树。位置套数值(当然也可以反着来,但在此题并没有优势)。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=40000000;
  4 char c;
  5 int n,m,cnt;
  6 int sum[N];
  7 int val[100050];
  8 int root[100050];
  9 int t[200050],tot;
 10 int son[N][2];
 11 int tl[100050];
 12 int tr[100050];
 13 struct node
 14 {
 15     int opt,l,r,pos,v;
 16 }num[100050];
 17 void modify(int &u,int l,int r,int pos,int v)
 18 {
 19     if(!u)    u=++cnt;
 20     sum[u]+=v;
 21     if(l==r)    return ;
 22     int mid=(l+r)>>1;
 23     if(pos<=mid)    modify(son[u][0],l,mid,pos,v);
 24     else    modify(son[u][1],mid+1,r,pos,v);
 25 }
 26 void calc_modify(int u,int v)
 27 {
 28     int tmp=lower_bound(t+1,t+tot+1,val[u])-t;
 29     for(int i=u;i<=n;i+=i&-i)    modify(root[i],1,tot,tmp,v);
 30 }
 31 int ask(int l,int r,int v)
 32 {
 33     if(l==r)    return l;
 34     int mid=(l+r)>>1,s=0;
 35     for(int i=1;i<=tr[0];++i)    s+=sum[son[tr[i]][0]];
 36     for(int i=1;i<=tl[0];++i)    s-=sum[son[tl[i]][0]];
 37     if(v<=s)
 38     {
 39         for(int i=1;i<=tr[0];++i)    tr[i]=son[tr[i]][0];
 40         for(int i=1;i<=tl[0];++i)    tl[i]=son[tl[i]][0];
 41         return ask(l,mid,v);
 42     }
 43     else
 44     {
 45         for(int i=1;i<=tr[0];++i)    tr[i]=son[tr[i]][1];
 46         for(int i=1;i<=tl[0];++i)    tl[i]=son[tl[i]][1];
 47         return ask(mid+1,r,v-s);
 48     }
 49 }
 50 int calc_ask(int l,int r,int v)
 51 {
 52     tl[0]=tr[0]=0;
 53     for(int i=r;i;i-=i&-i)    tr[++tr[0]]=root[i];
 54     for(int i=l-1;i;i-=i&-i)    tl[++tl[0]]=root[i];
 55     return ask(1,tot,v);
 56 }
 57 int rnk(int l,int r,int pos)
 58 {
 59     int s=0;
 60     if(r<=pos)
 61     {
 62         for(int i=1;i<=tr[0];++i)    s+=sum[tr[i]];
 63         for(int i=1;i<=tl[0];++i)    s-=sum[tl[i]];
 64         return s;
 65     }
 66     int mid=(l+r)>>1;
 67     if(pos>mid)
 68     {
 69         for(int i=1;i<=tr[0];++i)    s+=sum[son[tr[i]][0]],tr[i]=son[tr[i]][1];
 70         for(int i=1;i<=tl[0];++i)    s-=sum[son[tl[i]][0]],tl[i]=son[tl[i]][1];
 71         return s+rnk(mid+1,r,pos);
 72     }
 73     else if(pos>=l)
 74     {
 75         for(int i=1;i<=tr[0];++i)    tr[i]=son[tr[i]][0];
 76         for(int i=1;i<=tl[0];++i)    tl[i]=son[tl[i]][0];
 77         return rnk(l,mid,pos);    
 78     }
 79     else    return 0;
 80     
 81 }
 82 int calc_rnk(int l,int r,int v)
 83 {
 84     tl[0]=tr[0]=0;
 85     for(int i=r;i;i-=i&-i)    tr[++tr[0]]=root[i];
 86     for(int i=l-1;i;i-=i&-i)    tl[++tl[0]]=root[i];
 87     return rnk(1,tot,v);
 88 }
 89 int main()
 90 {
 91     scanf("%d%d",&n,&m);
 92     for(int i=1;i<=n;++i)
 93     {
 94         scanf("%d",&val[i]);
 95         t[++tot]=val[i];
 96     }
 97     for(int i=1;i<=m;++i)
 98     {
 99         scanf("%d",&num[i].opt);
100         if(num[i].opt==3)    scanf("%d%d",&num[i].pos,&num[i].v);
101         else    scanf("%d%d%d",&num[i].l,&num[i].r,&num[i].v);
102         if(num[i].opt!=2)    t[++tot]=num[i].v;
103     }
104     sort(t+1,t+tot+1);
105     tot=unique(t+1,t+tot+1)-t-1;
106     for(int i=1;i<=n;++i)
107         calc_modify(i,1);
108     for(int i=1;i<=m;++i)
109     {
110         if(num[i].opt==1)    printf("%d\n",calc_rnk(num[i].l,num[i].r,lower_bound(t+1,t+tot+1,num[i].v)-t-1)+1);
111         else if(num[i].opt==2)    printf("%d\n",t[calc_ask(num[i].l,num[i].r,num[i].v)]);
112         else if(num[i].opt==3)
113         {
114             calc_modify(num[i].pos,-1);
115             val[num[i].pos]=num[i].v;
116             calc_modify(num[i].pos,1);
117         }
118         else if(num[i].opt==4)
119         {
120             int tmp=calc_rnk(num[i].l,num[i].r,lower_bound(t+1,t+tot+1,num[i].v)-t-1);
121             if(tmp==0)    printf("-2147483647\n");
122             else printf("%d\n",t[calc_ask(num[i].l,num[i].r,tmp)]);
123         }
124         else
125         {
126             int tmp=calc_rnk(num[i].l,num[i].r,lower_bound(t+1,t+tot+1,num[i].v)-t);
127             if(tmp==num[i].r-num[i].l+1)    printf("2147483647\n");
128             else printf("%d\n",t[calc_ask(num[i].l,num[i].r,tmp+1)]);
129         }
130     }
131     return 0;
132 }
动态区间第k小

P4175 [CTSC2008]网络管理

        动态树上路径第k大。

        用 dfs 序将其转化为动态区间第 k 小。关键的是 dfs 序的应用。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int n,m,tot,ans;
  4 int x,y,opt,cnt;
  5 int f[100050][20];
  6 int deep[100050];
  7 int head[100050];
  8 int nex[200050];
  9 int ver[200050];
 10 int siz[100050];
 11 int val[100050];
 12 int root[100050];
 13 int sum[20000050];
 14 int son[20000050][2];
 15 int I[100050];
 16 int O[100050];
 17 int t[2000],top;
 18 int g[2000];
 19 void add(int x,int y)
 20 {
 21     nex[++tot]=head[x];
 22     ver[tot]=y;
 23     head[x]=tot;
 24 }
 25 void dfs(int u,int fa)
 26 {
 27     deep[u]=deep[fa]+1;    f[u][0]=fa;
 28     for(int k=1;k<=17;++k)
 29         f[u][k]=f[f[u][k-1]][k-1];
 30     I[u]=++tot;    siz[u]=1;
 31     for(int i=head[u];i;i=nex[i])
 32         if(ver[i]!=fa)
 33         {
 34             dfs(ver[i],u);
 35             siz[u]+=siz[ver[i]];
 36         }
 37     O[u]=I[u]+siz[u];
 38 }
 39 int lca(int x,int y)
 40 {
 41     if(deep[x]<deep[y])    swap(x,y);
 42     for(int i=17;i>=0;--i)
 43         if(deep[f[x][i]]>=deep[y])
 44             x=f[x][i];
 45     if(x==y)    return x;
 46     for(int i=17;i>=0;--i)
 47         if(f[x][i]!=f[y][i])
 48         {
 49             x=f[x][i];
 50             y=f[y][i];
 51         }
 52     return f[x][0];
 53 }
 54 void add(int &u,int l,int r,int pos,int val)
 55 {
 56     if(!u)    u=++tot;
 57     sum[u]+=val;
 58     if(l==r)    return ;
 59     int mid=(l+r)>>1;
 60     if(pos<=mid)    add(son[u][0],l,mid,pos,val);
 61     else    add(son[u][1],mid+1,r,pos,val);
 62 }
 63 void calc_add(int x,int y,int val)
 64 {
 65     for(int i=x;i<=n;i+=i&-i)
 66         add(root[i],0,1e8,y,val);
 67 }
 68 int ask(int l,int r)
 69 {
 70     if(l==r)    return l;
 71     int tmp=0;    int mid=(l+r)>>1;
 72     for(int i=1;i<=top;++i)
 73         tmp+=sum[son[t[i]][1]]*g[i];
 74     if(opt>tmp)
 75     {
 76         opt-=tmp;
 77         for(int i=1;i<=top;++i)
 78             t[i]=son[t[i]][0];
 79         return ask(l,mid);
 80     }
 81     else
 82     {
 83         for(int i=1;i<=top;++i)
 84             t[i]=son[t[i]][1];
 85         return ask(mid+1,r);
 86     }
 87 }
 88 void calc_ask(int u,int pos)
 89 {
 90     for(int i=u;i;i-=i&-i)
 91         if(root[i])
 92         {
 93             t[++top]=root[i];
 94             g[top]=pos;
 95         }
 96 }
 97 int main()
 98 {
 99     scanf("%d%d",&n,&m);
100     for(int i=1;i<=n;++i)
101         scanf("%d",&val[i]);
102     for(int i=1;i<n;++i)
103     {
104         scanf("%d%d",&x,&y);
105         add(x,y);    add(y,x);
106     }
107     tot=0;    dfs(1,0);    tot=0;
108     for(int i=1;i<=n;++i) 
109     {
110         calc_add(I[i],val[i],1);
111         calc_add(O[i],val[i],-1);
112     }
113     while(m--)
114     {
115         scanf("%d%d%d",&opt,&x,&y);
116         if(opt==0)
117         {
118             calc_add(I[x],val[x],-1);
119             calc_add(O[x],val[x],1);
120             val[x]=y;
121             calc_add(I[x],val[x],1);
122             calc_add(O[x],val[x],-1);    
123         }
124         else
125         {
126             int LCA=lca(x,y);
127             if(deep[x]+deep[y]-deep[LCA]*2+1<opt)
128             {
129                 printf("invalid request!\n");
130                 continue ;
131             }
132             top=0;
133             calc_ask(I[x],1);
134             calc_ask(I[y],1);
135             calc_ask(I[LCA],-1);
136             calc_ask(I[f[LCA][0]],-1);
137             printf("%d\n",ask(0,1e8));
138         }
139     }
140     return 0;
141 }
动态树上路径的k大

 


P3332 [ZJOI2013]K大数查询

        区间修改与区间查询。

        树套树的话,常数似乎会比较大。所以我写的是整体二分。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,tot;
 4 int ans[100050];
 5 struct node
 6 {
 7     int opt,l,r,pos;
 8     long long val;
 9 }num[100050],tl[100050],tr[100050];
10 long long c1[50050],c2[50050];
11 void add(int u,int v)
12 {
13     for(int i=u;i<=n;i+=i&-i)
14         c1[i]+=v,c2[i]+=v*u;
15 }
16 long long ask(int u)
17 {
18     long long tmp=0;
19     for(int i=u;i;i-=i&-i)
20         tmp+=(u+1)*c1[i]-c2[i];
21     return tmp;
22 }
23 void calc_add(int l,int r,int v)
24 {
25     add(l,v);    add(r+1,-v);
26 }
27 long long calc_ask(int l,int r)
28 {
29     return ask(r)-ask(l-1);
30 }
31 void calc(int L,int R,int l,int r)
32 {
33     if(l==r)
34     {
35         for(int i=L;i<=R;++i)    ans[num[i].pos]=l;
36         return ;
37     }
38     int mid=(l+r)>>1;
39     bool fl=0,fr=0;
40     int topl=0,topr=0;
41     for(int i=L;i<=R;++i)
42         if(num[i].opt==1)
43         {
44             if(num[i].val<=mid)
45                 tl[++topl]=num[i];
46             else
47             {
48                 calc_add(num[i].l,num[i].r,1);
49                 tr[++topr]=num[i];
50             }
51         }
52         else
53         {
54             long long tmp=calc_ask(num[i].l,num[i].r);
55             if(num[i].val>tmp)
56             {
57                 num[i].val-=tmp;
58                 fl=true;
59                 tl[++topl]=num[i];
60             }
61             else
62             {
63                 fr=true;
64                 tr[++topr]=num[i];
65             }
66         }
67     for(int i=L;i<=R;++i)
68         if(num[i].opt==1&&num[i].val>mid)
69             calc_add(num[i].l,num[i].r,-1);
70     for(int i=1;i<=topl;++i)    num[L+i-1]=tl[i];
71     for(int i=1;i<=topr;++i)    num[L+topl+i-1]=tr[i];
72     if(fl)    calc(L,L+topl-1,l,mid);
73     if(fr)    calc(L+topl,R,mid+1,r);
74 }
75 int main()
76 {
77     scanf("%d%d",&n,&m);
78     for(int i=1;i<=m;++i)
79     {
80         scanf("%d%d%d%lld",&num[i].opt,&num[i].l,&num[i].r,&num[i].val);
81         if(num[i].opt==2)    num[i].pos=++tot;
82     }
83     calc(1,m,-n,n);
84     for(int i=1;i<=tot;++i)    printf("%d\n",ans[i]);
85     return 0;
86 }
View Code

 


P3302 [SDOI2013]森林

        支持动态合并的树上路径第k小。(肯定在线啊。

        关于集合的合并有一种方式叫做启发式合并,这样会在静态的基础上多个log。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 char opt;
  4 int n,m,T,s,cnt;
  5 int x,y,z,a,b,ans;
  6 int val[100050];
  7 int t[100050],top;
  8 int f[100050][18];
  9 int deep[100050];
 10 int root[100050];
 11 int sum[40000050];
 12 int son[40000050][2];
 13 int head[100050],tot;
 14 int nex[200050],ver[200050];
 15 int siz[100050],anc[100050];
 16 int find(int u)
 17 {
 18     return anc[u]==u? u:anc[u]=find(anc[u]);
 19 }
 20 void add(int x,int y)
 21 {
 22     nex[++tot]=head[x];
 23     ver[tot]=y;
 24     head[x]=tot;
 25 }
 26 void build(int &u,int v,int l,int r,int pos)
 27 {
 28     u=++cnt;
 29     sum[u]=sum[v]+1;
 30     if(l==r)    return ;
 31     son[u][0]=son[v][0];
 32     son[u][1]=son[v][1];
 33     int mid=(l+r)>>1;
 34     if(pos<=mid)    build(son[u][0],son[v][0],l,mid,pos);
 35     else            build(son[u][1],son[v][1],mid+1,r,pos);
 36 }
 37 void dfs(int u,int fa)
 38 {
 39     deep[u]=deep[fa]+1;    f[u][0]=fa;
 40     for(int k=1;k<=17;++k)
 41         f[u][k]=f[f[u][k-1]][k-1];
 42     build(root[u],root[fa],1,top,val[u]);
 43     for(int i=head[u];i;i=nex[i])
 44         if(ver[i]!=fa)
 45             dfs(ver[i],u);
 46 }
 47 int lca(int x,int y)
 48 {
 49     if(deep[x]<deep[y])    swap(x,y);
 50     for(int i=17;i>=0;--i)
 51         if(deep[f[x][i]]>=deep[y])
 52             x=f[x][i];
 53     if(x==y)    return x;
 54     for(int i=17;i>=0;--i)
 55         if(f[x][i]!=f[y][i])
 56         {
 57             x=f[x][i];
 58             y=f[y][i];
 59         }
 60     return f[x][0];
 61 }
 62 void calc_add(int x,int y)
 63 {
 64     add(x,y);    add(y,x);
 65     int fx=find(x);
 66     int fy=find(y);
 67     if(siz[x]<siz[y])
 68     {
 69         swap(x,y);
 70         swap(fx,fy);
 71     }
 72     anc[fy]=fx;    siz[fx]+=siz[fy];
 73     dfs(y,x);
 74 }
 75 int calc_ask(int l,int r)
 76 {
 77     if(l==r)    return l;
 78     int tmp=sum[son[x][0]]+sum[son[y][0]];
 79     tmp-=sum[son[a][0]]+sum[son[b][0]];
 80     int mid=(l+r)>>1;
 81     if(z<=tmp)
 82     {
 83         x=son[x][0];    y=son[y][0];
 84         a=son[a][0];    b=son[b][0];
 85         return calc_ask(l,mid);
 86     }
 87     else
 88     {
 89         z-=tmp;
 90         x=son[x][1];    y=son[y][1];
 91         a=son[a][1];    b=son[b][1];
 92         return calc_ask(mid+1,r);
 93     }
 94 }
 95 int main()
 96 {
 97     scanf("%d%d%d%d",&s,&n,&m,&T);
 98     for(int i=1;i<=n;++i)
 99     {
100         scanf("%d",&val[i]);
101         t[i]=val[i];
102         anc[i]=i;
103         siz[i]=1;
104     }
105     sort(t+1,t+n+1);
106     top=unique(t+1,t+n+1)-t-1;
107     for(int i=1;i<=n;++i)
108         val[i]=lower_bound(t+1,t+top+1,val[i])-t;
109     while(m--)
110     {
111         scanf("%d%d",&x,&y);
112         add(x,y);    add(y,x);
113         int fx=find(x);
114         int fy=find(y);
115         anc[fy]=fx;
116         siz[fx]+=siz[fy];
117     }
118     for(int i=1;i<=n;++i)
119         if(!root[i])
120             dfs(i,0);
121     while(T--)
122     {
123         scanf(" %c%d%d",&opt,&x,&y);
124         x^=ans;    y^=ans;
125         if(opt=='Q')
126         {
127             scanf("%d",&z);
128             z^=ans;
129             a=lca(x,y);
130             b=f[a][0];
131             x=root[x];    y=root[y];
132             a=root[a];    b=root[b];
133             ans=t[calc_ask(1,top)];
134             printf("%d\n",ans);
135         }
136         else
137             calc_add(x,y);
138     }
139     return 0;
140 }
支持动态合并的树上路径第k小

 

posted @ 2019-02-24 10:54  Hevix  阅读(836)  评论(1编辑  收藏  举报