BZOJ 3123: [Sdoi2013]森林

3123: [Sdoi2013]森林

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 2914  Solved: 853
[Submit][Status][Discuss]

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

Sample Output

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。之后的操作类似。 

 

 

Source

分析:

如果没有L操作就很好办了,直接维护每个节点的到根节点的路径上的权值线段树,然后加加减减就好了...

现在有L操作就是说我们要合并两棵树以及更新每个节点的信息,那么因为要更新信息,所以一定是要遍历一遍某课子树,所以我们采用启发式合并主席树,每一次重新dfs小的那棵树重建每个节点的权值权值线段树...

时间复杂度$O(Nlog^{2}N)$...然而我的比别人的跑的都慢...加了快读才勉强卡过去...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=200000+5,maxm=40000000+5;

int n,m,t,T,cas,cnt,len,tot,w[maxn],mp[maxn],ls[maxm],rs[maxm],hd[maxn],fa[maxn][25],to[maxn],nxt[maxn],sum[maxm],dep[maxn],siz[maxn],vis[maxn],root[maxn],father[maxn];

inline int read(void){
	char ch=getchar();int x=0,f=1;
	while(!(ch>='0'&&ch<='9')){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
		x=x*10+ch-'0',ch=getchar();
	return f*x;
}

inline int Find(int x){
	return father[x]==x?x:father[x]=Find(father[x]);
}

inline int find(int x){
	int _=1,__=len,___;
	while(_<=__){
		int ____=(_+__)>>1;
		if(mp[____]>=x)
			___=____,__=____-1;
		else
			_=____+1;
	}
	return ___;
}

inline void add(int x,int y){
	to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
}

inline void change(int l,int r,int x,int &y,int val){
    y=++tot,sum[y]=sum[x]+1;
    if(l==r)
        return;
    int mid=(l+r)>>1;ls[y]=ls[x],rs[y]=rs[x];
    if(val<=mid)
        change(l,mid,ls[x],ls[y],val);
    else
        change(mid+1,r,rs[x],rs[y],val);
}

inline int LCA(int x,int y){
    if(dep[x]<dep[y])
        swap(x,y);
    int d=dep[x]-dep[y];
    for(int i=0;i<=20;i++)
        if((d>>i)&1)
            x=fa[x][i];
    if(x==y)
        return x;
    for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

inline void dfs(int rt){
	vis[rt]=T;change(1,len,fa[rt][0]==rt?root[0]:root[fa[rt][0]],root[rt],find(w[rt]));
	for(int j=1;j<=20;j++)
		fa[rt][j]=fa[fa[rt][j-1]][j-1];
	for(int i=hd[rt];i!=-1;i=nxt[i])
		if(vis[to[i]]!=T)
			fa[to[i]][0]=rt,dep[to[i]]=dep[rt]+1,dfs(to[i]);
}

inline int query(int l,int r,int x,int y,int lca,int flca,int num){
    if(l==r)
        return l;
    int mid=(l+r)>>1;
    if(sum[ls[x]]+sum[ls[y]]-sum[ls[lca]]-sum[ls[flca]]>=num)
        return query(l,mid,ls[x],ls[y],ls[lca],ls[flca],num);
    else
        return query(mid+1,r,rs[x],rs[y],rs[lca],rs[flca],num-(sum[ls[x]]+sum[ls[y]]-sum[ls[lca]]-sum[ls[flca]]));
}

signed main(void){
	cas=read();
	cnt=0;len=0;tot=0;T=1;
	memset(hd,-1,sizeof(hd));
	n=read();m=read();t=read();
	for(int i=1;i<=n;i++)
		w[i]=read(),mp[i]=w[i];
	sort(mp+1,mp+n+1);len=unique(mp+1,mp+n+1)-mp-1;
	for(int i=1,x,y;i<=m;i++)
		x=read(),y=read(),add(x,y),add(y,x);
	for(int i=1;i<=n;i++)
		father[i]=i,siz[i]=1;
	for(int i=1;i<=n;i++)
		if(vis[i]!=T)
			dep[i]=0,fa[i][0]=i,dfs(i);
	T++;char opt[3];int ans=0;
	for(int i=1,s,x,y;i<=t;i++){
		scanf("%s",opt);
		if(opt[0]=='Q'){
			x=read(),y=read(),s=read();x=x^ans,y=y^ans,s=s^ans;
			int lca=LCA(x,y);
			printf("%d\n",ans=mp[query(1,len,root[x],root[y],root[lca],fa[lca][0]==lca?root[0]:root[fa[lca][0]],s)]);
		}
		else{
			x=read(),y=read();x=x^ans,y=y^ans;
			int fx=Find(x),fy=Find(y);
			if(siz[fx]>siz[fy])
				swap(x,y),swap(fx,fy);
			fa[x][0]=y,dep[x]=dep[y]+1,dfs(x),add(x,y),add(y,x);father[fx]=fy,siz[fy]+=siz[fx];T++;
		}
	}
	return 0;
}

  


By NeighThorn

posted @ 2017-02-14 08:44  NeighThorn  阅读(240)  评论(0编辑  收藏  举报