生活随笔
收集整理的這篇文章主要介紹了
P5787 二分图 /【模板】线段树分治
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意:
思路:
線段樹分治就是在線段樹上進行遍歷,到每個點都加上它對子節點的貢獻,最后到葉子節點的時候算一下貢獻。
對于這個題先考慮維護二分圖的話,可以用擴展域并查集維護。
而對于每條邊,他有出現時間和消失時間,我們按照時間來建一顆線段樹,讓后可以將他出現的時間[l,r][l,r][l,r]在線段樹上切分成lognlognlogn段,對于每段都分別管理著不同的葉子節點。我們可以用vectorvectorvector存下來管理當前這顆子樹的邊,讓后把他們連上,判斷一下是否是二分圖,不是的話當前[l,r][l,r][l,r]時間段都不是二分圖,否則就繼續遍歷,最后回溯的時候用可撤銷并查集撤銷一下就好了。
注意并查集不能路徑壓縮,因為我們還要撤銷。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
,k
;
int p
[N
],se
[N
];
PII edge
[N
];
stack
<PII
>s
;
struct Node
{int l
,r
;vector
<int>v
;
}tr
[N
<<2];void build(int u
,int l
,int r
)
{tr
[u
]={l
,r
};if(l
==r
) return;build(L
,l
,Mid
); build(R
,Mid
+1,r
);
}void insert(int u
,int l
,int r
,int id
)
{if(tr
[u
].l
>=l
&&tr
[u
].r
<=r
){tr
[u
].v
.push_back(id
);return;}if(l
<=Mid
) insert(L
,l
,r
,id
);if(r
>Mid
) insert(R
,l
,r
,id
);
}int find(int x
) { return x
==p
[x
]? x
:find(p
[x
]); }void merge(int a
,int b
)
{if(a
==b
) return;if(se
[a
]<se
[b
]) swap(a
,b
);p
[b
]=a
; se
[a
]+=se
[b
];s
.push({b
,se
[b
]});
}void dfs(int u
,int l
,int r
)
{int flag
=1,beg
=s
.size();for(int i
=0;i
<tr
[u
].v
.size();i
++){int id
=tr
[u
].v
[i
];int pa
=find(edge
[id
].X
),pb
=find(edge
[id
].Y
);if(pa
==pb
) { flag
=0; break; }merge(pa
,find(edge
[id
].Y
+n
)),merge(find(edge
[id
].X
+n
),pb
);}if(flag
){if(l
==r
) puts("Yes");else dfs(L
,l
,Mid
),dfs(R
,Mid
+1,r
);}else for(int i
=l
;i
<=r
;i
++) puts("No");while(s
.size()>beg
) se
[find(s
.top().X
)]-=s
.top().Y
,p
[s
.top().X
]=s
.top().X
,s
.pop();
}int main()
{
scanf("%d%d%d",&n
,&m
,&k
);for(int i
=1;i
<=n
*2;i
++) p
[i
]=i
,se
[i
]=1;build(1,1,k
);for(int i
=1;i
<=m
;i
++){int x
,y
,l
,r
; scanf("%d%d%d%d",&x
,&y
,&l
,&r
);if(l
!=r
) insert(1,l
+1,r
,i
);edge
[i
]={x
,y
};}dfs(1,1,k
);return 0;
}
總結
以上是生活随笔為你收集整理的P5787 二分图 /【模板】线段树分治的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。