Monkeying Around 线段树+树状数组
来源:互联网 发布:yum 不支持python 2.7 编辑:程序博客网 时间:2024/06/05 23:47
题目大意,给定若干(Li, Ri, Ki)表示Li到Ri的人都得到一个标号为ki的球,依次进行。n个人每个人有一个状态0或者1,如果在这次操作前已经有过ki这种球了,那么状态会变成0,否则变成1.初始的时候都是0.求m次操作后有多少个0.
题解:一开始想错了,后来发现是个傻逼提。唯一需要考虑的性质是,每个人的最终状态 基 本 上 由最后一次覆盖到他的操作的ki决定。(题面是经过一点点转化的,所以现在看起来很显然)。
如果第i个人没有被任何区间覆盖,那么最后显然是0.
假设第i个人最后拿到的球的编号是ai,如果他拿了两次及以上的ai,那么状态是0,否则是1.
因此首先用线段树处理出每个人最后一个得到的球的编号。然后枚举球的编号x,把ki=x的区间+1,检查那些最后得到x的人时候只被覆盖一次即可,这部分显然树状数组一下即可。如果代码实现不好需要特判一下没有拿到球的人。注意多组数据。
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<vector>#define N 100010#define lb(x) (x&-x)#define solve(s,t,v) update(s,v),update(t+1,-v)using namespace std;struct segment{ int l,r,v; segment *ch[2];}*rt;int n;struct node{ int L,R; node(int l,int r) { L=l,R=r; } inline node operator=(const node &n) { L=n.L,R=n.R;return *this; }};vector<int> v[N];vector<node> q[N];int build(segment* &rt,int l,int r){ rt=new segment;rt->l=l,rt->r=r,rt->v=0; if(l==r) return 0;int mid=(l+r)>>1; build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r); return 0;}int Clear(segment* &rt){ int l=rt->l,r=rt->r;rt->v=0;if(l==r) return 0; return Clear(rt->ch[0]),Clear(rt->ch[1]);}inline int push_down(segment* &rt){ rt->ch[0]->v=rt->v; rt->ch[1]->v=rt->v; return rt->v=0;}int update(segment* &rt,int s,int t,int v){ int l=rt->l,r=rt->r,mid=(l+r)>>1; if(s<=l&&r<=t) return rt->v=v; if(rt->v) push_down(rt); if(s<=mid) update(rt->ch[0],s,t,v); if(mid<t) update(rt->ch[1],s,t,v); return 0;}int PUSH(segment* &rt){ int l=rt->l,r=rt->r; if(l==r) return (l<=n?v[rt->v].push_back(l),0:0),0; if(rt->v) push_down(rt); PUSH(rt->ch[0]),PUSH(rt->ch[1]); return 0;}int c[N];inline void update(int x,int v){ for(;x<=n;x+=lb(x)) c[x]+=v;}inline int query(int x){ int ans=0; for(;x;x-=lb(x)) ans+=c[x]; return ans;}int main(){ int T;scanf("%d",&T);build(rt,1,N); while(T--) { int m;scanf("%d%d",&n,&m); Clear(rt);int maxl=0; for(int i=0;i<N;i++) v[i].clear(),q[i].clear(); for(int i=1,x,l,k;i<=m;i++) { scanf("%d%d%d",&x,&l,&k),maxl=max(maxl,l); update(rt,max(1,x-k),min(n,x+k),l); q[l].push_back(node(max(1,x-k),min(n,x+k))); } PUSH(rt);int ans=0; for(int i=1;i<=maxl;i++) { for(int j=0;j<q[i].size();j++) solve(q[i][j].L,q[i][j].R,1); for(int j=0;j<v[i].size();j++) if(query(v[i][j])==1) ans++; for(int j=0;j<q[i].size();j++) solve(q[i][j].L,q[i][j].R,-1); } printf("%d\n",n-ans+v[0].size()); } return 0;}
阅读全文