【SDOI2013 R1 Day1】森林

题目大意

给一个森林,森林有n个节点m条边,总共有T次操作。
操作分为两种:
1.Q x y k 表示询问x-y这条链上点权的第k小。保证x,y在同一个连通块里。
2.L x y 表示链接x,y两点。保证x,y在不同的连通块里。

输入格式

第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1<=testcase<=20。 第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。 接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为”Q x y k“或者”L x y “。要求强制在线,lastans表示上一次的答案,每次x,y,k都要异或lastans。lastans初始为0。

输出格式

对于每一个第一类操作,输出一个非负整数表示答案。

样例输入 1

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

样例输出 1

2
2
1
4
2
1

样例输入 2

20 12 20
412060525 42425138 67114752 160822495 201962681 926214957 380263349 733667141 869039239 641017702 154667400 461702107 438851950 176272938 209229857 985208975 762952138 936593832 409183276 999506034
2 17
4 1
15 3
3 10
9 10
7 16
19 15
13 2
6 2
3 14
7 18
8 15
Q 6 17 2
Q 762952152 762952154 762952139
L 380263329 380263352
L 380263357 380263333
Q 380263356 380263359 380263348
L 641017709 641017703
L 641017716 641017700
Q 641017716 641017704 641017698
Q 380263359 380263357 380263345
L 733667140 733667136
L 733667150 733667156
L 733667145 733667142
Q 733667149 733667145 733667140
Q 67114772 67114761 67114759
Q 733667145 733667159 733667142
Q 380263359 380263356 380263351
Q 869039233 869039232 869039237
Q 380263359 380263345 380263356
Q 733667136 733667140 733667143
Q 412060537 412060516 412060519

样例输出 2

762952138
380263349
641017702
380263349
733667141
67114752
733667141
380263349
869039239
380263349
733667141
412060525
985208975

数据范围

这里写图片描述


题解

询问操作稍微简单一点。我们用一点差分数组的思想,预处理每个点到根节点的路径上所有权值出现个数(这当然是主席树)。这样对于每个询问(x,y),这条路径上某一段区间中的数出现的个数就是x 点到根的加上y 点到根的减去两点的最近公共祖先到根的减去祖先的父亲到根的。
修改操作之前做题时看懵了。然而,正解是一个叫启发式合并的东西。简单说,就是把节点数少的树换根,重新遍历一遍。一次遍历的期望时间复杂度是O( l o g 2 N )。
再提醒一下,testcase是测试点编号,并不是多组询问,之前没注意到,T了很久。。。


代码

#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
int f[90001][22],n,cnt[30000000],ls[30000000],rs[30000000],tot,s,v[80005],dep[80005],si[800005];
int nn[322222],last[380005],e[322222],inc;
void add(int x,int y)
{
    e[++inc]=y;
    nn[inc]=last[x];
    last[x]=inc;
}
int Lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    int del=dep[x]-dep[y],i;
    for(i=s;i>=0;--i)
        if((del>>i)&1)
            x=f[x][i];
    if(x==y)return x;
    for(i=s;i>=0;--i)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
void xiu(int now,int last,int l,int r,int x)
{
    cnt[now]=cnt[last]+1;
    if(l==r)return;
    int mid=(l+r)>>1;
    ls[now]=ls[last];
    rs[now]=rs[last];
    if(x<=mid)ls[now]=++tot,xiu(ls[now],ls[last],l,mid,x);
    else rs[now]=++tot,xiu(rs[now],rs[last],mid+1,r,x);
}
void dfs(int x)
{
    int i,t,y;
    si[x]=1;
    for(i=1;i<=s;i++)
        f[x][i]=f[f[x][i-1]][i-1];
    if(f[x][0]==x)xiu(x,0,0,1e9,v[x]);
    else xiu(x,f[x][0],0,1e9,v[x]);
    for(t=last[x];t;t=nn[t])
    {
        y=e[t];
        if(y==f[x][0])continue;
        f[y][0]=x,dep[y]=dep[x]+1;
        dfs(y);
        si[x]+=si[y];
    }
}
int get(int x,int y,int lca1,int lca2,int l,int r,int k)
{
    cnt[0]=0;
    if(l==r)return l;
    int mid=(l+r)>>1,temp=cnt[ls[x]]+cnt[ls[y]]-cnt[ls[lca1]]-cnt[ls[lca2]];
    if(k<=temp)return get(ls[x],ls[y],ls[lca1],ls[lca2],l,mid,k);
    return get(rs[x],rs[y],rs[lca1],rs[lca2],mid+1,r,k-temp);
}
void solve()
{
    char omg[10];
    int ans=0,i,n,t,m,x,y;
    scanf("%d%d%d",&n,&m,&t);
    tot=n,inc=0;
    s=int(floor(log2(n)))+1;
    for(i=1;i<=n;i++)
        scanf("%d",&v[i]);
    for(i=1;i<=m;i++)
        scanf("%d%d",&x,&y),add(x,y),add(y,x);
    for(i=1;i<=n;i++)
        if(!dep[i])
            f[i][0]=i,dep[i]=1,dfs(i);
    while(t--)
    {
        scanf("%s",omg);
        if(omg[0]=='Q')
        {
            scanf("%d%d%d",&x,&y,&i);
            x^=ans,y^=ans,i^=ans;
            int huaji=Lca(x,y);
            if(f[huaji][0]!=huaji)ans=get(x,y,huaji,f[huaji][0],0,1e9,i);
            else ans=get(x,y,huaji,0,0,1e9,i);
            printf("%d\n",ans);
        }
        else{
            scanf("%d%d",&x,&y);
            x^=ans,y^=ans;
            int fx=f[x][s],fy=f[y][s];
            if(si[fx]<si[fy])swap(x,y),swap(fx,fy);
            f[y][0]=x;
            si[fx]+=si[fy];
            dep[y]=dep[x]+1;
            add(x,y),add(y,x);
            dfs(y);
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/includelhc/article/details/79752009