CodeForces - 1217F Forced Online Queries Problem(线段树分治+并查集撤销)
題目鏈接:點擊查看
題目大意:給出 nnn 個點,初始時互相不存在連邊,需要執行 mmm 次操作,每次操作分為兩種類型:
詢問需要強制在線
題目分析:關于強制在線實現連邊與加邊,如果是在樹上進行的話可以用 LCTLCTLCT,但如果放在圖上的話好像是可以用 ETTETTETT,不過這個題目需要看出這個強制在線是個假的,所以可以離線去做
之前做過一道類似的題目:牛客多校8 - All-Star Game
所以這個題目考慮用線段樹分治離線去做,將每個節點視為詢問的時間點,遞歸的時候實現并查集的加邊,回溯的時候實現并查集的撤銷即可,訪問到葉子節點時回答每個詢問并且更新后續的詢問
然后關鍵點就是如何將題目轉換成離線去做,因為上一次的答案只可能為 000 或 111,所以對于一對詢問 (x,y)(x,y)(x,y) 來說,只可能是 (x,y)(x,y)(x,y) 或 (xmodn+1,ymodn+1)(x \bmod n+1,y\bmod n+1)(xmodn+1,ymodn+1),對于操作二的話無傷大雅,直接存起來下面會講如何更新,而對于操作一來說,線段樹分治的本質就是將 (x,y)(x,y)(x,y) 這條邊的出現時間到刪除時間的這段區間打上標記,所以我們可以在讀入時就將所有的 (x,y)(x,y)(x,y) 點對都壓入到線段樹中
舉個很簡單的例子,假設 (x,y)(x,y)(x,y) 這條邊的出現位置共有三次,分別是 t1,t2,t3t_1,t_2,t_3t1?,t2?,t3?,我們先不用管哪個時間點是刪除,哪個時間點是增加,直接將所有的連續區間都打上標記,諸如:[t1,t2],[t2,t3],[t3,m][t_1,t_2],[t_2,t_3],[t_3,m][t1?,t2?],[t2?,t3?],[t3?,m]( mmm 是詢問的個數,相當于最后的一個時間點),然后在分治的過程中,根據實際的詢問去選擇是否加邊
最后說一下如何實時更新出實際的詢問以及加邊,因為線段樹遞歸到葉子節點的順序一定是從左到右下去的,所以當遞歸到葉子節點 xxx 時,x?1x-1x?1 一定結束了,且 x+1x+1x+1 一定還沒有被訪問過,利用這個特點每次詢問完葉子節點 xxx 后可以順便將 x+1x+1x+1 位置的詢問更新一下
代碼:
// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<unordered_map> using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=2e5+100; struct{int op,x,y;}q[N]; map<pair<int,int>,int>mp; int f[N],rk[N],ans[N],last,n,m; struct revo {int fax,fay;int rkx,rky; }; struct Node {int l,r;vector<pair<int,int>>node;//位于[l,r]這段時間內的邊有哪些 }tree[N<<2]; int find(int x){return f[x]==x?x:find(f[x]);} revo merge(int x,int y)//并查集的合并,返回合并之前的信息revo用于撤銷 {revo ans;int xx=find(x),yy=find(y);ans.fax=xx,ans.fay=yy;ans.rkx=rk[xx],ans.rky=rk[yy];if(xx!=yy){if(rk[xx]>rk[yy]) swap(xx,yy);f[xx]=yy;rk[yy]=max(rk[yy],rk[xx]+1);}return ans; } void revocation(stack<revo>&st)//并查集的撤銷,將并查集恢復至node狀態 {while(st.size()){revo a=st.top();f[a.fax]=a.fax,f[a.fay]=a.fay;rk[a.fax]=a.rkx,rk[a.fay]=a.rky;st.pop();} } void build(int k,int l,int r) {tree[k].l=l,tree[k].r=r;if(l==r) return;int mid=(l+r)>>1;build(k<<1,l,mid),build(k<<1|1,mid+1,r); } void update(int k,int l,int r,pair<int,int>val) {if(l>r) return;if(tree[k].l>r||tree[k].r<l) return;if(tree[k].l>=l&&tree[k].r<=r){tree[k].node.push_back(val);return;}update(k<<1,l,r,val),update(k<<1|1,l,r,val); } void dfs(int k)//線段樹分治 {stack<revo>st;for(auto it:tree[k].node) if(mp[it]) st.push(merge(it.first,it.second));//并查集的合并if(tree[k].l==tree[k].r){int id=tree[k].l;if(q[id].op==2) last=ans[id]=(find(q[id].x)==find(q[id].y));q[id+1].x=(q[id+1].x+last-1)%n+1,q[id+1].y=(q[id+1].y+last-1)%n+1;if(q[id+1].x>q[id+1].y) swap(q[id+1].x,q[id+1].y);if(q[id+1].op==1) mp[{q[id+1].x,q[id+1].y}]^=1;revocation(st);return;}else dfs(k<<1),dfs(k<<1|1);revocation(st); } void init(){for(int i=1;i<N;i++) f[i]=i,rk[i]=1;} int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();read(n),read(m);build(1,1,m);for(int i=1,x,y,op;i<=m;i++){read(op),read(x),read(y);q[i]={op,x,y};if(op==2) continue;if(x>y) swap(x,y);if(mp[{x,y}]) update(1,mp[{x,y}],i,{x,y});mp[{x,y}]=i;x=x%n+1,y=y%n+1;if(x>y) swap(x,y);if(mp[{x,y}]) update(1,mp[{x,y}],i,{x,y});mp[{x,y}]=i;}for(auto it:mp) update(1,it.second,m,it.first);mp.clear();if(q[1].op==1) mp[{min(q[1].x,q[1].y),max(q[1].x,q[1].y)}]=1;memset(ans,-1,sizeof(ans));dfs(1);for(int i=1;i<=m;i++) if(ans[i]!=-1) write(ans[i]);return 0; }總結
以上是生活随笔為你收集整理的CodeForces - 1217F Forced Online Queries Problem(线段树分治+并查集撤销)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 916D Ja
- 下一篇: CodeForces - 1207F R