第一行包含一个正整数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。之后的操作类似。
可持久化线段树+启发式合并
如果只有查询操作,每次询问找到两个点的LCA,然后用可持久化线段树加加减减查询第k大即可。
对于连接操作我们要用启发式合并,把小的集合合并到大的上面,并把小的暴力重建主席树。
这样时间和空间复杂度就是O(n*logn^2)。
这道题我调了好久好久...后来要了数据才发现即使testcase>1也只有一组数据hhhh...数据坑爹怪我吗
然而把这个改了还是RE,原来是加边的cnt和主席树的cnt搞混了...啊啊啊欲哭无泪
#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define N 100005
#define M 40000000
#define inf 1000000000
using namespace std;
int n,m,t,cnt,cnt_e,ans;
int a[N],head[N],rt[N],f[N],sum[N],dep[N],fa[N][20];
int sz[M],ls[M],rs[M];
struct edge_type{int next,to;}e[N*2];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void add_edge(int x,int y)
{
e[++cnt_e]=(edge_type){head[x],y};head[x]=cnt_e;
e[++cnt_e]=(edge_type){head[y],x};head[y]=cnt_e;
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void merge(int x,int y)
{
int fx=find(x),fy=find(y);
f[fx]=fy;sum[fy]+=sum[fx];
}
int lca(int x,int y)
{
if (dep[x]=dep[y]) x=fa[x][i];
if (x==y) return x;
D(i,19,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void insert(int x,int &y,int l,int r,int val)
{
if (!y) y=++cnt;
sz[y]=sz[x]+1;
if (l==r) return;
int mid=(l+r)>>1;
if (val<=mid) rs[y]=rs[x],insert(ls[x],ls[y],l,mid,val);
else ls[y]=ls[x],insert(rs[x],rs[y],mid+1,r,val);
}
int getkth(int x,int y,int z,int w,int l,int r,int k)
{
if (l==r) return l;
int mid=(l+r)>>1;
int tmp=sz[ls[x]]+sz[ls[y]]-sz[ls[z]]-sz[ls[w]];
if (k<=tmp) return getkth(ls[x],ls[y],ls[z],ls[w],l,mid,k);
else return getkth(rs[x],rs[y],rs[z],rs[w],mid+1,r,k-tmp);
}
void dfs(int x)
{
F(i,1,19) fa[x][i]=fa[fa[x][i-1]][i-1];
dep[x]=dep[fa[x][0]]+1;
rt[x]=0;
insert(rt[fa[x][0]],rt[x],0,inf,a[x]);
for(int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0])
{
fa[e[i].to][0]=x;
dfs(e[i].to);
}
}
int main()
{
int hhh=read();
n=read();m=read();t=read();
F(i,1,n) a[i]=read();
F(i,1,n) f[i]=i,sum[i]=1;
F(i,1,m)
{
int x=read(),y=read();
add_edge(x,y);merge(x,y);
}
F(i,1,n) if (!fa[i][0]) dfs(i);
F(i,1,t)
{
char opt=getchar();while (opt!='Q'&&opt!='L') opt=getchar();
if (opt=='Q')
{
int x=read()^ans,y=read()^ans,k=read()^ans,lc=lca(x,y);
ans=getkth(rt[x],rt[y],rt[lc],rt[fa[lc][0]],0,inf,k);
printf("%d\n",ans);
}
else
{
int x=read()^ans,y=read()^ans,fx=find(x),fy=find(y);
if (sum[fx]>sum[fy]) swap(x,y);
add_edge(x,y);merge(x,y);
fa[x][0]=y;dfs(x);
}
}
return 0;
}