在一条数轴上有N个点,分别是1~N。一开始所有的点都被染成黑色。接着
我们进行M次操作,第i次操作将[Li,Ri]这些点染成白色。请输出每个操作执行后
剩余黑色点的个数。
输入一行为N和M。下面M行每行两个数Li、Ri
输出M行,为每次操作后剩余黑色点的个数。
10 3
3 3
5 7
2 8
9
6
3
数据限制
对30%的数据有1<=N<=2000,1<=M<=2000
对100%数据有1<=Li<=Ri<=N<=200000,1<=M<=200000
#include<iostream> #include<cstdio> using namespace std; int sum,tot=0; struct treetype { int Left,Right; //区间[Left,Right) int lptr,rptr; //左右孩子指针 int sum; //区间和 int bj; //标记 }t[2000000]; void buildtree(int ll,int rr) { int cur=++tot; t[cur].Left=ll; t[cur].Right=rr; if(ll!=rr-1) { t[cur].lptr=tot+1; buildtree(ll,(ll+rr)/2); t[cur].rptr=tot+1; buildtree(+(ll+rr)/2,rr); t[cur].sum=t[t[cur].lptr].sum+t[t[cur].rptr].sum; }else t[cur].sum=1; } void update(int k) //延迟信息下传 { t[t[k].lptr].sum=0; t[t[k].rptr].sum=0; //左右子区间清空 t[t[k].lptr].bj=1; t[t[k].rptr].bj=1; //传递标志 t[k].bj=0; //清除标志 } void change(int k,int ll,int rr) //修改区间[ll,rr)元素的值 { if (ll<=t[k].Left&&rr>=t[k].Right) //覆盖当前区间 { t[k].sum=0; //区间和=0 t[k].bj=1; //设标志 } else { if(t[k].bj) update(k); //传递修改 if (ll<(t[k].Left+t[k].Right)/2) //修改左区间 change(t[k].lptr,ll,rr); if (rr>(t[k].Left+t[k].Right)/2) //修改右区间 change(t[k].rptr,ll,rr); t[k].sum=t[t[k].lptr].sum+t[t[k].rptr].sum; //更新区间和 } } int query(int k,int ll,int rr) //查询[ll,rr)区间和 { if (ll<=t[k].Left&&rr>=t[k].Right) return t[k].sum; if (t[k].bj) update(k); //传递修改 int ans=0; if (ll<(t[k].Left+t[k].Right)/2) ans+=query(t[k].lptr,ll,rr); if (rr>(t[k].Left+t[k].Right)/2) ans+=query(t[k].rptr,ll,rr); return ans; } int main() { int n,tim,x,y; scanf("%d%d",&n,&tim); sum=n; buildtree(1,n+1); for (int i=1;i<=tim;i++) { scanf("%d%d",&x,&y); change(1,x,y+1); printf("%d\n",query(1,1,n+1)); } return 0; }
原文:http://www.cnblogs.com/liumengyue/p/5107358.html