第一行包含一个正整数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<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #include<queue> 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 <int> 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<<LOG) >= 0; ++LOG); --LOG; for (int i = LOG; i >= 0; i--) if (L[p] - (1<<i) >= 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; }