题目(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; }
Comments NOTHING