第一行包含一个正整数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小值用主席树轻松解决,对于加边,使用启发式合并暴力重建
复杂度O(nlog^2n)
MLE一次也是醉
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 8E4 + 10;
const int ml = 17;
int n,m,t,c[maxn*32*ml],lc[maxn*32*ml],rc[maxn*ml*32],root[maxn];
int cnt,cur,ans,anc[maxn][ml],fa[maxn],siz[maxn],num[maxn],a[maxn],L[maxn];
bool vis[maxn];
vector v[maxn];
int father(int k) {return k == fa[k]?k:fa[k]=father(fa[k]);}
int Insert(int o,int l,int r,int pos)
{
int ret = ++cnt;
c[ret] = c[o] + 1;
if (l == r) return ret;
int mid = (l+r) >> 1;
if (pos <= mid) rc[ret] = rc[o],lc[ret] = Insert(lc[o],l,mid,pos);
else lc[ret] = lc[o],rc[ret] = Insert(rc[o],mid+1,r,pos);
return ret;
}
int build(int x,int from)
{
root[x] = Insert(root[from],1,cur,a[x]);
anc[x][0] = from;
for (int i = 1; i < ml; i++) anc[x][i] = anc[anc[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++) {
int to = v[x][i];
if (to == from) continue;
vis[to] = 1;
L[to] = L[x]+1;
build(to,x);
}
}
int lca(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
int LOG;
for (LOG = 0; L[p] - (1<= 0; ++LOG); --LOG;
for (int i = LOG; i >= 0; i--)
if (L[p] - (1<= L[q])
p = anc[p][i];
if (p == q) return p;
for (int i = LOG; i >= 0; i--)
if (anc[p][i] != anc[q][i]) {
p = anc[p][i];
q = anc[q][i];
}
return anc[p][0];
}
int query(int o1,int o2,int o3,int o4,int l,int r,int k)
{
if (l == r) return num[l];
int mid = (l+r) >> 1;
int tot = c[lc[o1]] + c[lc[o2]] - c[lc[o3]] - c[lc[o4]];
if (tot >= k) return query(lc[o1],lc[o2],lc[o3],lc[o4],l,mid,k);
else return query(rc[o1],rc[o2],rc[o3],rc[o4],mid+1,r,k-tot);
}
int main()
{
#ifdef YZY
freopen("yzy.txt","r",stdin);
#endif
int tc; cin >> tc >> n >> m >> t;
for (int i = 1; i <= n; i++) scanf("%d",&a[i]),num[i] = a[i];
sort(num+1,num+n+1);
cur = 1;
for (int i = 2; i <= n; i++)
if (num[i] != num[i-1])
num[++cur] = num[i];
for (int i = 1; i <= n; i++) {
a[i] = lower_bound(num+1,num+cur+1,a[i])-num;
fa[i] = i; siz[i] = 1;
}
while (m--) {
int x,y; scanf("%d%d",&x,&y);
int fx = father(x),fy = father(y);
if (fx != fy) {
fa[fx] = fy;
siz[fy] += siz[fx];
}
v[x].push_back(y); v[y].push_back(x);
}
for (int i = 1; i <= n; i++)
if (!vis[i]) L[i] = 1,vis[i] = 1,build(i,0);
while (t--) {
char c = getchar();
while (c != 'L' && c != 'Q') c = getchar();
int x,y,k; scanf("%d%d",&x,&y);
x ^= ans; y ^= ans;
if (c == 'L') {
int fx = father(x),fy = father(y);
v[x].push_back(y); v[y].push_back(x);
if (siz[fx] < siz[fy]) swap(x,y);
L[y] = L[x] + 1; build(y,x);
}
else {
scanf("%d",&k); k ^= ans;
int LCA = lca(x,y);
ans = query(root[x],root[y],root[LCA],root[anc[LCA][0]],1,cur,k);
printf("%d\n",ans);
}
}
return 0;
}