主席树,启发式合并LCA.
每个节点在其父节点的基础上建权值线段树。
对于询问(x,y),设lca为其最近公共祖先,则答案由val[x]+val[y]-val[lca]-val[fa[lca]]决定,这与静态区间第k小数的做法一致。
对于连接操作(x,y).我们用启发式合并维护倍增数组。启发式合并的同时,暴力构建主席树。
虽然大家都是这么做的,但我不明白为什么人家代码3k,而我的代码有5k,而且还跑得很慢.
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 105000
#define MS 18
#define MAXM 20000000
int limit=0;
struct node
{
int val,ls,rs;
node()
{
val=ls=rs=0;
}
}tr[MAXM];
int root[MAXN],fa[MAXN][MS+2],val[MAXN],dep[MAXN];
int n,m,T,lstans,tot;
void _r(int& x)
{
char c=getchar();
while(c<'0'||c>'9')
{
c=getchar();
}
for(x=0;c>='0'&&c<='9';c=getchar())
{
x=(x<<1)+(x<<3)+c-'0';
}
return ;
}
void ins(int& p,int f,int l,int r,int x)
{
p=++tot;
tr[p]=tr[f];
tr[p].val++;
if(l<r)
{
int mid=(l+r)>>1;
if(x<=mid)
{
ins(tr[p].ls,tr[f].ls,l,mid,x);
}
else
{
ins(tr[p].rs,tr[f].rs,mid+1,r,x);
}
}
return ;
}
int qa,qb,qc,qd;
int query(int l,int r,int k)
{
if(l==r)
{
return l;
}
int num,mid=(l+r)>>1;
int a=tr[qa].ls,b=tr[qb].ls,c=tr[qc].ls,d=tr[qd].ls;
num=tr[a].val+tr[b].val-tr[c].val-tr[d].val;
if(k<=num)
{
qa=a;
qb=b;
qc=c;
qd=d;
return query(l,mid,k);
}
else
{
qa=tr[qa].rs;
qb=tr[qb].rs;
qc=tr[qc].rs;
qd=tr[qd].rs;
return query(mid+1,r,k-num);
}
}
bool vis[MAXN];
queue<int>bfs;
int Next[MAXN<<1],Last[MAXN],End[MAXN<<1],e=1;
void add(int x,int y)
{
End[++e]=y;
Next[e]=Last[x];
Last[x]=e;
return ;
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])
{
swap(x,y);
}
int k=dep[x]-dep[y];
for(int i=MS;i>=0;i--)
{
if(k>>i&1)
{
x=fa[x][i];
}
}
if(x==y)
{
return x;
}
for(int i=MS;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
int o[15],oo;
void _w(int x)
{
if(x==0)
{
putchar('0');
return ;
}
for(oo=0;x;x/=10)
{
o[++oo]=x%10;
}
for(;oo;--oo)
{
putchar('0'+o[oo]);
}
return ;
}
int bl[MAXN],size[MAXN];
void link(int x,int y)
{
bfs.push(x);
fa[x][0]=y;
dep[x]=dep[y]+1;
int u,v;
while(bfs.size())
{
u=bfs.front();
bfs.pop();
bl[u]=bl[y];
size[bl[y]]++;
for(int i=1;i<=MS;i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
ins(root[u],root[fa[u][0]],1,limit,val[u]);
for(int t=Last[u];t;t=Next[t])
{
v=End[t];
if(v!=fa[u][0])
{
fa[v][0]=u;
dep[v]=dep[u]+1;
bfs.push(v);
}
}
}
add(x,y);
add(y,x);
return ;
}
int main()
{
int testcase;
_r(testcase);
_r(n);
_r(m);
_r(T);
for(int i=1;i<=n;i++)
{
_r(val[i]);
limit=max(limit,val[i]);
}
for(int i=1,x,y;i<=m;i++)
{
_r(x);
_r(y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
int u,v;
if(!vis[i])
{
bfs.push(i);
vis[i]=1;
ins(root[i],0,1,limit,val[i]);
while(bfs.size())
{
u=bfs.front();
bfs.pop();
bl[u]=i;
size[i]++;
for(int t=Last[u];t;t=Next[t])
{
v=End[t];
if(!vis[v])
{
vis[v]=1;
bfs.push(v);
fa[v][0]=u;
ins(root[v],root[u],1,limit,val[v]);
dep[v]=dep[u]+1;
for(int k=1;k<=MS;k++)
{
fa[v][k]=fa[fa[v][k-1]][k-1];
}
}
}
}
}
}
char s[3];
for(int i=1,x,y,k;i<=T;i++)
{
scanf("%s",s);
if(s[0]=='Q')
{
_r(x);
_r(y);
_r(k);
x^=lstans;
y^=lstans;
k^=lstans;
int lca=LCA(x,y);
qa=root[x];
qb=root[y];
qc=root[lca];
qd=root[fa[lca][0]];
lstans=query(1,limit,k);
_w(lstans);
putchar('\n');
}
else
{
_r(x);
_r(y);
x^=lstans;
y^=lstans;
if(size[bl[x]]>size[bl[y]])
{
swap(x,y);
}
link(x,y);
}
}
return 0;
}