[bzoj1103]-[POI2007]大都市meg

发布于 2018-02-19  142 次阅读



题目(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\
				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(
	sort(ans+1,ans+n+1);
	for (int i=1;i<=n;++i)if(ans[i])printf(
	return 0;
}