zoukankan      html  css  js  c++  java
  • 区间(树上)第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
    ",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
    ",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
    ",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
    ",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
    ",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
    ");
    122             else printf("%d
    ",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
    ");
    128             else printf("%d
    ",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!
    ");
    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
    ",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
    ",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
    ",ans);
    135         }
    136         else
    137             calc_add(x,y);
    138     }
    139     return 0;
    140 }
    支持动态合并的树上路径第k小
  • 相关阅读:
    火币Huobi API Websocket
    火币Huobi API
    OKEX API(Websocket)
    OKEX API
    Linux下Miniconda量化环境安装
    Numba:高性能Python编译器
    十进制和十六进制互相转换
    JavaScript 原型和原型链
    Redux 进阶之 react-redux 和 redux-thunk 的应用
    Vue 中 $nextTick() 的应用
  • 原文地址:https://www.cnblogs.com/wyher/p/10425531.html
Copyright © 2011-2022 走看看