zoukankan      html  css  js  c++  java
  • [SDOI2013]森林

    [SDOI2013]森林

    题目大意:

    一个(n(nle8 imes10^4))个点的森林,每个结点有一个权值(w_i)(q(qle8 imes10^4))次操作,操作包含以下两种:

    1. 查询(x)(y)的路径中,第(k)小的权值是多少;
    2. 连接(x)(y)

    思路:

    如果本来就是一棵树,那么显然可以用主席树来维护。

    由于现在是一个森林,那么每次将较小的树合并到较大的树上,并重构较小的子树对应的主席树,同时重新维护倍增LCA的相关信息。

    空间上注意内存回收。

    时间复杂度(mathcal O(nlog^2n))

    源代码:

    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    inline char getalpha() {
    	register char ch;
    	while(!isalpha(ch=getchar()));
    	return ch;
    }
    const int N=8e4+1,logN=18;
    int w[N],tmp[N],dep[N],anc[N][logN];
    std::vector<int> e[N];
    inline void add_edge(const int &u,const int &v) {
    	e[u].push_back(v);
    	e[v].push_back(u);
    }
    inline int lg2(const float &x) {
    	return ((unsigned&)x>>23&255)-127;
    }
    inline int lca(int x,int y) {
    	if(dep[x]<dep[y]) std::swap(x,y);
    	for(register int i=lg2(dep[x]-dep[y]);i>=0;i--) {
    		if(dep[anc[x][i]]>=dep[y]) x=anc[x][i];
    	}
    	for(register int i=lg2(dep[x]);i>=0;i--) {
    		if(anc[x][i]!=anc[y][i]) {
    			x=anc[x][i];
    			y=anc[y][i];
    		}
    	}
    	return x==y?x:anc[x][0];
    }
    class DisjointSet {
    	private:
    		int anc[N],size[N];
    		int find(const int &x) {
    			return x==anc[x]?x:anc[x]=find(anc[x]);
    		}
    	public:
    		void reset(const int &n) {
    			std::fill(&size[1],&size[n]+1,1);
    			for(register int i=1;i<=n;i++) anc[i]=i;
    		}
    		int count(const int &x) {
    			return size[find(x)];
    		}
    		void merge(const int &x,const int &y) {
    			int p=find(x),q=find(y);
    			if(size[p]>size[q]) std::swap(p,q);
    			anc[p]=q;
    			size[q]+=size[p];
    		}
    };
    DisjointSet s;
    class FotileTree {
    	#define mid ((b+e)>>1)
    	private:
    		struct Node {
    			int val,left,right;
    		};
    		Node node[N*logN];
    		std::deque<int> q;
    		int new_node(const int &p) {
    			const int ret=q.front();
    			q.pop_front();
    			node[ret]=node[p];
    			return ret;
    		}
    		void del_node(const int &p) {
    			q.push_back(p);
    		}
    	public:
    		int root[N];
    		FotileTree() {
    			for(register int i=1;i<N*logN;i++) {
    				q.push_back(i);
    			}
    		}
    		void insert(int &p,const int &b,const int &e,const int &x) {
    			p=new_node(p);
    			node[p].val++;
    			if(b==e) return;
    			if(x<=mid) insert(node[p].left,b,mid,x);
    			if(x>mid) insert(node[p].right,mid+1,e,x);
    		}
    		void erase(const int &p,const int &b,const int &e,const int &x) {
    			del_node(p);
    			if(b==e) return;
    			if(x<=mid) erase(node[p].left,b,mid,x);
    			if(x>mid) erase(node[p].right,mid+1,e,x);
    		}
    		int query(const int &p,const int &q,const int &r,const int &s,const int &b,const int &e,const int &k) const {
    			if(b==e) return b;
    			int tmp=0;
    			tmp+=node[node[p].left].val;
    			tmp+=node[node[q].left].val;
    			tmp-=node[node[r].left].val;
    			tmp-=node[node[s].left].val;
    			if(tmp>=k) return query(node[p].left,node[q].left,node[r].left,node[s].left,b,mid,k);
    			return query(node[p].right,node[q].right,node[r].right,node[s].right,mid+1,e,k-tmp);
    		}
    	#undef mid
    };
    FotileTree t;
    void dfs(const int &x,const int &par) {
    	memset(anc[x],0,sizeof anc[x]);
    	anc[x][0]=par;
    	dep[x]=dep[par]+1;
    	for(register int i=1;i<=lg2(dep[x]);i++) {
    		anc[x][i]=anc[anc[x][i-1]][i-1];
    	}
    	t.erase(t.root[x],1,tmp[0],w[x]);
    	t.insert(t.root[x]=t.root[par],1,tmp[0],w[x]);
    	for(unsigned i=0;i<e[x].size();i++) {
    		const int &y=e[x][i];
    		if(y==par) continue;
    		dfs(y,x);
    	}
    }
    inline void link(int x,int y) {
    	if(s.count(x)>s.count(y)) {
    		std::swap(x,y);
    	}
    	dfs(x,y);
    	s.merge(x,y);
    	add_edge(x,y);
    }
    inline int query(const int &x,const int &y,const int &k) {
    	const int z=lca(x,y),w=anc[z][0];
    	return tmp[t.query(t.root[x],t.root[y],t.root[z],t.root[w],1,tmp[0],k)];
    }
    int main() {
    	getint();
    	const int n=getint(),m=getint(),q=getint();
    	for(register int i=1;i<=n;i++) {
    		tmp[i]=w[i]=getint();
    	}
    	std::sort(&tmp[1],&tmp[n]+1);
    	tmp[0]=std::unique(&tmp[1],&tmp[n]+1)-&tmp[1];
    	for(register int i=1;i<=n;i++) {
    		w[i]=std::lower_bound(&tmp[1],&tmp[tmp[0]]+1,w[i])-tmp;
    		dep[i]=1;
    		t.insert(t.root[i],1,tmp[0],w[i]);
    	}
    	s.reset(n);
    	for(register int i=0;i<m;i++) {
    		link(getint(),getint());
    	}
    	for(register int i=0,ans=0;i<q;i++) {
    		const char opt=getalpha();
    		const int x=getint()^ans,y=getint()^ans;
    		if(opt=='Q') {
    			printf("%d
    ",ans=query(x,y,getint()^ans));
    		}
    		if(opt=='L') link(x,y);
    	}
    	return 0;
    }
    
  • 相关阅读:
    JAVA应用apache httpclient探测http服务
    C#中字符串与byte[]相互转换
    C#中位、字节等知识
    #JAVA操作LDAP
    C#正则表达式判断字符串是否是金钱
    【IDEA】使用Maven骨架创建JavaWeb项目
    【IDEA】回退操作记录
    【SpringMVC】IDEA 不识别webapp的解决办法
    【Layui】16 表单元素 Form
    【Layui】15 日期时间选择器 Laydate
  • 原文地址:https://www.cnblogs.com/skylee03/p/9645946.html
Copyright © 2011-2022 走看看