题意:给你一个不完整的出入会议的记录,让你判断谁可能是领导,领导必须在其他人在场的时候都在场。
思路:可以将现有的记录转换为若干个区间,如果这个区间被其他区间包含,则这个区间所代表的人不是领导。
当然,记录不完整,有的只有出去的记录,这就需要补上他进来的,我这里默认补在0时间,当然也有只进没出的,默认把他的出时间定在m+1时刻。由于树状数组是从1开始,所以维护时将他们的出入时间默认加1就可以了。
有些人的出入记录没有涉及,那么这些人都可能是领导。对于有记录的人,这些人中只可能有1个领导,如果他们的进出区间有满足领导性质的区间数超过1时(后面有其他区间使得这个人不是领导的那个人的区间也算,只看单个区间),那么这些有记录的人则都不可能是领导。
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<algorithm> #include<cmath> #include<string> #include<vector> #include<queue> using namespace std; struct node { int l,r,num; }; int n,m,mm; vector<node>v; vector<int>ren; int p[111111]; bool vis[111111]; bool ans[111111]; char s[3]; int a; int c[111111]; int lowbit(int x) { return x&(-x); } void add(int x,int y) { for(int i=x;i<=mm;i+=lowbit(i)) { c[i]+=y; } } int sum(int x) { int ss=0; for(int i=x;i>0;i-=lowbit(i))ss+=c[i]; return ss; } int main() { scanf("%d%d",&n,&m); mm=m+2; memset(p,0,sizeof(p)); memset(vis,0,sizeof(vis)); for(int i=1;i<=m;i++) { scanf("%s%d",s,&a); if(s[0]=='+')p[a]=i; else { v.push_back((node){p[a]+1,i+1,a}); p[a]=0; } ren.push_back(a); } ren.erase(unique(ren.begin(),ren.end()),ren.end()); int rsize=ren.size(); int nnn=0; for(int i=1;i<=n;i++) { if(p[i]) { v.push_back((node){p[i]+1,m+2,i}); } } int size=v.size(); for(int i=0;i<size;i++) { add(v[i].l,1); add(v[i].r,-1); //cout<<v[i].l<<" "<<v[i].r<<" "<<v[i].num<<endl; } memset(ans,0,sizeof(ans)); for(int i=0;i<size;i++) { if(sum(v[i].r)!=0||(v[i].l!=1&&sum(v[i].l)!=1)) { ans[v[i].num]=1; //cout<<v[i].num<<" "<<sum(v[i].r)<<" "<<sum(v[i].l)<<"!!"<<endl; } else if(!vis[v[i].num]) { vis[v[i].num]=1; nnn++; } } if(nnn>1) { //cout<<1<<endl; for(int i=0;i<rsize;i++) { ans[ren[i]]=1; //cout<<ren[i]<<endl; } } int cnt=0; for(int i=1;i<=n;i++) { if(!ans[i])cnt++; } cout<<cnt<<endl; for(int i=1;i<=n;i++) { if(!ans[i])printf("%d ",i); } cout<<endl; return 0; }