Description
Input
第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。
Output
对于每一个第一类操作,输出一个非负整数表示答案。
Sample Input
1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6
Sample Output
2
2
1
4
2
2
1
4
2
HINT
对于第一个操作 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。之后的操作类似。
人生第一发启发式合并???woc这tm就是主席树啊还启发式合并
这道题有点像永无乡,都是暴力拆掉小的树
但是我现在还是搞不懂它这个一点都不合情理的空间复杂度和时间复杂度
据说能很快??据说空间很小??不是很懂
不知道怎么树上主席树的童鞋看我博客吧(不要脸)
代码如下:
#include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; struct LSnode{ int id,pos; }A[210000];int rank[210000]; bool cmp(LSnode a,LSnode b){return a.id<b.id;} struct trnode{ int lc,rc,c; }t[21110000];int cnt; struct node{ int x,y,next; }a[210000];int len,last[210000]; int n,m,T,lastans; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int father[210000]; int findfa(int x) { if(father[x]!=x)father[x]=findfa(father[x]); return father[x]; } int tot[210000],rt[210000]; void Link(int &u,int l,int r,int p) { if(u==0)u=++cnt; t[u].c++; if(l==r)return ; int mid=(l+r)/2; if(p<=mid)Link(t[u].lc,l,mid,p); else Link(t[u].rc,mid+1,r,p); } void Merge(int &u1,int u2) { if(!u1||!u2){u1=u1+u2;return ;} t[u1].c+=t[u2].c; Merge(t[u1].lc,t[u2].lc); Merge(t[u1].rc,t[u2].rc); } int findans(int u1,int u2,int u,int v,int l,int r,int K) { if(l==r)return A[l].id; int mid=(l+r)/2; int c=t[t[u1].lc].c+t[t[u2].lc].c-t[t[u].lc].c-t[t[v].lc].c; if(K<=c)return findans(t[u1].lc,t[u2].lc,t[u].lc,t[v].lc,l,mid,K); else return findans(t[u1].rc,t[u2].rc,t[u].rc,t[v].rc,mid+1,r,K-c); } void del(int u) { t[u].c=0; int lc=t[u].lc,rc=t[u].rc; if(t[lc].c>0&&rc)del(lc); if(t[rc].c>0&&lc)del(rc); t[u].lc=t[u].rc=0; } int bin[25],fa[110000][25],dep[110000]; void ch(int x,int f) { dep[x]=dep[f]+1;fa[x][0]=f; del(rt[x]);Link(rt[x],1,n,rank[x]);Merge(rt[x],rt[f]); for(int i=1;bin[i]<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=f)ch(y,x); } } void pre_tree_node(int x) { for(int i=1;bin[i]<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1]; Link(rt[x],1,n,rank[x]);Merge(rt[x],rt[fa[x][0]]); for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x][0]) { fa[y][0]=x; dep[y]=dep[x]+1; pre_tree_node(y); } } } int lca(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=20;i>=0;i--)if(bin[i]<=dep[x] && dep[fa[x][i]]>=dep[y])x=fa[x][i]; if(x==y)return x; for(int i=20;i>=0;i--)if(bin[i]<=dep[x] && fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } char ss[10]; int main() { int TT; scanf("%d",&TT); len=0;memset(last,0,sizeof(last)); memset(rt,0,sizeof(rt)); cnt=0; scanf("%d%d%d",&n,&m,&T); for(int i=1;i<=n;i++)scanf("%d",&A[i].id),A[i].pos=i; sort(A+1,A+1+n,cmp); for(int i=1;i<=n;i++)rank[A[i].pos]=i; bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]*2; len=0;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++)father[i]=i,tot[i]=1; for(int i=1;i<=m;i++) { int x,y;scanf("%d%d",&x,&y); ins(x,y);ins(y,x); int p=findfa(x),q=findfa(y); if(p!=q) { father[p]=q; tot[q]+=tot[p]; } } for(int i=1;i<=n;i++) if(dep[i]==0) fa[i][0]=0,dep[i]=1,pre_tree_node(i); lastans=0; while(T--) { int u,v,k; scanf("%s%d%d",ss+1,&u,&v); u^=lastans;v^=lastans; if(ss[1]=='Q') { scanf("%d",&k);k^=lastans; int tmp=lca(u,v); lastans=findans(rt[u],rt[v],rt[tmp],rt[fa[tmp][0]],1,n,k); printf("%d\n",lastans); } else { int p=findfa(u),q=findfa(v); int tx=tot[p],ty=tot[q]; if(tx<ty) { ins(u,v);ins(v,u); ch(u,v); tot[q]+=tot[p];father[p]=q; } else { ins(u,v);ins(v,u); ch(v,u); tot[p]+=tot[q];father[q]=p; } } } return 0; }
by_lmy