[SDOI2013]森林
阿新 • • 發佈:2018-09-14
nts nod front n) merge back getchar() let char
[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[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\n",ans=query(x,y,getint()^ans)); } if(opt=='L') link(x,y); } return 0; }
[SDOI2013]森林