题目(BZOJ)
题目(洛谷)
dfs序的另一巧妙运用。
来说一下这题吧
先对树从根节点开始做一遍dfs序,记录每个点进入和出去时间,在进入时打上1,出去时打上-1;
然后,对于修改操作,只需要看y就行了...
在y点的进入时间打上-1,出去时间打上1,
最后对于每个查询操作,只需要查询到当前点的进入时间的前缀和,并且-1,就搞腚了。
整个过程可以用树状数组解决。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <cctype>
#include <vector>
#include <climits>
#include <ext/pb_ds/assoc_container.hpp>
#define llmax LLONG_MAX
#define llmin LLONG_MIN
using namespace std;
using namespace __gnu_pbds;
template <class _E> inline void read(_E &e){
e=0;bool ck=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')ck=1;ch=getchar();}
while(isdigit(ch)){e=(e<<1)+(e<<3)+(ch^48);ch=getchar();}
if(ck)e=-e;
}
const int N=100050;
int n,m,ans[N],tot;
bool vis[N];
struct options{
int u,v;
}p[2000050];
int f[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
inline bool cmp(const options &x,const options &y){
if (x.u==y.u) return x.v<y.v;
else return x.u<y.u;
}
int main(){
read(n),read(m);
for (int i=1;i<=m;++i){
read(p[i].u),read(p[i].v);
}
for (int i=1;i<=n;++i) f[i]=i;
sort(p+1,p+m+1,cmp);
int now=0,px;
for (int i=1;i<=m;++i){
if (p[i].u!=p[i-1].u){
if(p[i].u-p[i-1].u>1){
printf("1\n%d ",n);
return 0;
}
while(now<n&&p[i-1].u!=0){
++now;
int py=find(now);
if(px!=py)f[px]=py;
}
px=find(p[i].u);
now=p[i].u;
}
++now;
while(now<p[i].v){
int py=find(now);
if(px!=py)f[px]=py;
++now;
}
}
for (int i=1;i<=n;++i){
ans[find(i)]++;
}
for (int i=1;i<=n;++i){
int p=find(i);
if(ans[p]&&!vis[p]) ++tot,vis[p]=1;
}
printf("%d\n",tot);
sort(ans+1,ans+n+1);
for (int i=1;i<=n;++i)if(ans[i])printf("%d ",ans[i]);
return 0;
}






Comments NOTHING