第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。
对于每一个第一类操作,输出一个非负整数表示答案。
对于第一个操作 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大,是树上主席树的经典问题。
我们在树上主席树的基础上需要做的就是启发式合并,其实就是每次讲小一点的树暴力重建到大树上。
码力题。。。
#include
#include
#include
#include
#include
#define N 160003
using namespace std;
int tot,sz,n,m,q;
int root[N],point[N],next[N*2],v[N*2],belong[N],ff[N][20],fa[N],num[N],b[N],val[N],c[N];
int deep[N],mi[20],vis[N],cnt,q1[N],size[N];
struct data
{
int l,r,w;
}tr[40000000];
void init()
{
tot=0; sz=0; deep[0]=0;
memset(point,0,sizeof(point));
tr[0].w=tr[0].l=tr[0].r=0;
memset(fa,0,sizeof(fa));
memset(vis,0,sizeof(vis));
memset(root,0,sizeof(root));
}
void add(int x,int y)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x;
}
int cmp(int x,int y)
{
return val[x]=k) return query(l,mid,k,tr[x].l,tr[y].l,tr[z].l,tr[d].l);
else return query(mid+1,r,k-t,tr[x].r,tr[y].r,tr[z].r,tr[d].r);
}
void dfs(int x,int f)
{
vis[x]=1; deep[x]=deep[f]+1;
for (int i=1;i<=17;i++){
if (deep[x]-mi[i]<0) ff[x][i]=0;
ff[x][i]=ff[ff[x][i-1]][i-1];
}
root[x]=root[f];
insert(root[x],1,n,c[x]);
for (int i=point[x];i;i=next[i]) {
if (vis[v[i]]||v[i]==f) continue;
fa[v[i]]=x; ff[v[i]][0]=x;
dfs(v[i],x);
}
}
void solve(int x,int f,int dep)
{
fa[x]=f; ff[x][0]=f; deep[x]=dep;
for (int i=1;i<=17;i++){
if (deep[x]-mi[i]<0) ff[x][i]=0;
ff[x][i]=ff[ff[x][i-1]][i-1];
}
root[x]=root[f];
insert(root[x],1,n,c[x]);
for (int i=point[x];i;i=next[i]) {
if (v[i]==f) continue;
ff[v[i]][0]=x;
solve(v[i],x,dep+1);
}
}
int find(int x)
{
if (belong[x]==x) return x;
belong[x]=find(belong[x]);
return belong[x];
}
int lca(int x,int y)
{
if (deep[x]>i&1) x=ff[x][i];
if (x==y) return x;
for (int i=17;i>=0;i--)
if (ff[x][i]!=ff[y][i])
x=ff[x][i],y=ff[y][i];
return ff[x][0];
}
int main()
{
freopen("rforest.in","r",stdin);
freopen("rforest.out","w",stdout);
int T;
scanf("%d",&T); T=1;
mi[0]=1;
for (int i=1;i<=17;i++) mi[i]=mi[i-1]*2;
for(int t=1;t<=T;t++) {
init();
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=n;i++) scanf("%d",&val[i]),b[i]=i;
sort(b+1,b+n+1,cmp);
for (int i=1;i<=n;i++) c[b[i]]=i,num[i]=val[b[i]];
for (int i=1;i<=n;i++) belong[i]=i,size[i]=1;
for (int i=1;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
add(x,y);
int r1=find(x); int r2=find(y);
if (size[r1]size[r2]) swap(x,y),swap(r1,r2);
belong[r1]=r2; size[r2]+=size[r1];
solve(x,y,deep[y]+1);
add(x,y);
}
if (s[0]=='Q'){
scanf("%d",&k); k^=ans;
int t=lca(x,y);
ans=query(1,n,k,root[x],root[y],root[t],root[fa[t]]);
ans=num[ans];
printf("%d\n",ans);
}
}
}
}