[SDOI2013]森林
2018-09-14 13:08
281 查看
[SDOI2013]森林
题目大意:
一个\(n(n\le8\times10^4)\)个点的森林,每个结点有一个权值\(w_i\)。\(q(q\le8\times10^4)\)次操作,操作包含以下两种:
- 查询\(x\)到\(y\)的路径中,第\(k\)小的权值是多少;
- 连接\(x\)和\(y\)。
思路:
如果本来就是一棵树,那么显然可以用主席树来维护。
由于现在是一个森林,那么每次将较小的树合并到较大的树上,并重构较小的子树对应的主席树,同时重新维护倍增LCA的相关信息。
空间上注意内存回收。
时间复杂度\(\mathcal O(n\log^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 ,tmp ,dep ,anc [logN]; std::vector<int> e ; 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 ,size ; 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 +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 ; 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 +1); tmp[0]=std::unique(&tmp[1],&tmp +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\n",ans=query(x,y,getint()^ans)); } if(opt=='L') link(x,y); } return 0; }
相关文章推荐
- [SDOI2013]森林
- [BZOJ3123][Sdoi2013]森林(主席树+启发式合并)
- 【SDOI2013】森林
- BZOJ3123: [Sdoi2013]森林
- [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+倍增lca+启发式合并)
- [bzoj3123][SDOI2013]森林
- AC日记——[Sdoi2013]森林 bzoj 3123
- [SDOI2013]森林
- 3123: [Sdoi2013]森林 主席树的启发式合并
- BZOJ 3123: [Sdoi2013]森林 启发式合并 树上主席树
- 【bzoj3123】 [Sdoi2013]森林
- BZOJ2123 [Sdoi2013]森林 【主席树 + 启发式合并】
- bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)
- 【bzoj3132】 Sdoi2013—森林
- BZOJ 3123 SDOI2013 森林
- BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
- [luoguP3302] [SDOI2013]森林(主席树 + 启发式合并 + lca)
- [SDOI2013] 森林
- bzoj3123: [Sdoi2013]森林
- 【SDOI2013 R1 Day1】森林