• 【bzoj3132】 Sdoi2013—森林


    http://www.lydsy.com/JudgeOnline/problem.php?id=3123 (题目链接)

    题意

      给出$n$个点的森林,每个点有一个非负点权,$m$个操作。连接两个点,查询两个点之间路径上的第$K$大点权。强制在线。

    Solution

      主席树+启发式合并。

      对于查询操作,主席树维护区间第$K$大即可,当前节点新建的节点是在其父亲节点基础上建立的,也就是说这个主席树维护的是到根的路径。

      对于连接操作,直接启发式合并暴力搞过去就可以了,记得同时更新$size$和$fa$以及重建主席树。

    细节

      原来不是多组数据,只是当前数据对应的是数据范围的第几个部分分,好良心的主题人啊→_→

      果然using namespace 就清晰很多,调过样例就直接过了。

    代码

    // bzoj3123
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define lim 1000000000
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    
    const int maxn=100010;
    int Dargen[maxn],size[maxn],deep[maxn],head[maxn],fa[maxn][30],bin[30];
    int n,m,Q,sz,ans,cnt,a[maxn],rt[maxn];
    struct edge {int to,next;}e[maxn<<1];
    struct node {
    	int son[2],s;
    	void clear() {son[0]=son[1]=0;s=0;}
    	int& operator [] (int x) {return son[x];}
    }tr[maxn*40];
    
    namespace Chairtree {
    	void build(int &u,int v,int l,int r,int val) {
    		if (!u) u=++sz;
    		if (l==r) {tr[u].s=tr[v].s+1;return;}
    		int mid=(l+r)>>1;
    		if (val<=mid) build(tr[u][0],tr[v][0],l,mid,val),tr[u][1]=tr[v][1];
    		else build(tr[u][1],tr[v][1],mid+1,r,val),tr[u][0]=tr[v][0];
    		tr[u].s=tr[tr[u][0]].s+tr[tr[u][1]].s;
    	}
    	void merge(int x,int y) {
    		build(rt[x],rt[y],0,lim,a[x]);
    		Dargen[x]=Dargen[y];fa[x][0]=y;
    		deep[x]=deep[y]+1;
    		for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    		for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
    				merge(e[i].to,x);
    				size[x]+=size[e[i].to];
    			}
    	}
    	int query(int u,int v,int w,int x,int l,int r,int K) {
    		if (l==r) return l;
    		int mid=(l+r)>>1,c=tr[tr[u][0]].s+tr[tr[v][0]].s-tr[tr[w][0]].s-tr[tr[x][0]].s;
    		if (c>=K) return query(tr[u][0],tr[v][0],tr[w][0],tr[x][0],l,mid,K);
    		else return query(tr[u][1],tr[v][1],tr[w][1],tr[x][1],mid+1,r,K-c);
    	}
    }
    using namespace Chairtree;
    
    namespace Tree {
    	void link(int u,int v) {
    		e[++cnt]=(edge){v,head[u]};head[u]=cnt;
    		e[++cnt]=(edge){u,head[v]};head[v]=cnt;
    	}
    	void dfs(int x) {
    		size[x]=1;build(rt[x],rt[fa[x][0]],0,lim,a[x]);
    		Dargen[x]=fa[x][0] ? Dargen[fa[x][0]] : x;
    		for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    		for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
    				fa[e[i].to][0]=x;
    				deep[e[i].to]=deep[x]+1;
    				dfs(e[i].to);
    				size[x]+=size[e[i].to];
    			}
    	}
    	int lca(int x,int y) {
    		if (deep[x]<deep[y]) swap(x,y);
    		int t=deep[x]-deep[y];
    		for (int i=0;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
    		for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    		return x==y ? x : fa[x][0];
    	}
    }
    using namespace Tree;
    
    int main() {
    	char ch[10];int T;scanf("%d",&T);
    	bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
    	scanf("%d%d%d",&n,&m,&Q);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for (int u,v,i=1;i<=m;i++) {
    		scanf("%d%d",&u,&v);
    		link(u,v);
    	}
    	for (int i=1;i<=n;i++) if (!size[i]) dfs(i);
    	for (int x,y,K,i=1;i<=Q;i++) {
    		scanf("%s%d%d",ch,&x,&y);
    		x^=ans,y^=ans;
    		if (ch[0]=='L') {
    			link(x,y);
    			if (size[Dargen[x]]>size[Dargen[y]]) swap(x,y);
    			size[Dargen[y]]+=size[Dargen[x]];
    			merge(x,y);
    		}
    		if (ch[0]=='Q') {
    			scanf("%d",&K);
    			K^=ans;
    			int f=lca(x,y);
    			ans=query(rt[x],rt[y],rt[f],rt[fa[f][0]],0,lim,K);
    			printf("%d
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    制作自适应布局的模块及框架(转载)
    从今天起开始写博了
    工作中碰到的css问题解决方法
    标题写个什么好呢
    快速编写HTML(Zen conding)
    2013年1月21日记事
    opc 方面研究
    关于 部署方面研究 Visual Studio 2013
    intel AVX指令集
    关于 返回数据类型 后 加& 的作用
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6481449.html
Copyright © 2020-2023  润新知