第一行包含一个正整数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<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #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]) swap(x,y); D(i,19,0) if (dep[fa[x][i]]>=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; }