[ZOJ 3324][BNUOJ 16842] Machine [线段树]

来源:互联网 发布:linux渗透测试工具 编辑:程序博客网 时间:2024/05/29 18:59

有一个神奇的机器,它由一排按键构成,在这种机器上有两种操作,第一种是同时按下[l,r]的所有键,第二种是释放[l,r]的所有键。所有的释放操作均对应一个同区间的按下操作,并且释放操作在按下操作后边进行。若一个按键被按下两次释放一次,则其还是被按下的。现在给定若干次操作,问每次操作后没有被按下的键的段数。如果一段区间[l,r]里的所有的键都没有被按下,那么他们算作一段。

数据范围:总长度不超过10^8,操作次数不超过20000

先对数据离散化,因为只有2W次操作,操作又是成对出现的,所以最多出现2W个不同的点,假使每两个点之间都还有其他的点,这些点永远是相同状态的所以可以缩成一个点。这样最多有4W个叶子节点。

线段树,用类似矩形面积并里边的线段树的那种算法,每个节点记录自己被按下了多少次,然后记录自己的状态,包含左边是否被按下,右边是否被按下,中间有多少个被按下的段。如果该段是整体被按下,则中间被按下的段记录为-1。没有懒操作。仅在某个节点的所有祖先节点都没有被按下的情况下,这个节点的信息才是有效的,否则这个结点一定是全被按下的。

#include <cstdio>#include <cstring>#include <map>#include <set>using namespace std;struct State{bool l,r;int n;State() {n=-1;l=r=true;}State(bool ll,bool rr,int nn) {l=ll;r=rr;n=nn;}};struct Opt {int l,r;bool p;void read() {char c;scanf(" %c",&c);p=(c=='p');scanf("%d%d",&l,&r);}};struct Node {int l,r,times;State s;Node *ls,*rs;Node() {}Node(int ll,int rr) {l=ll;r=rr;ls=rs=NULL;s=State();times=0;}void update() {if (times!=0) {s=State(false,false,0);return;}s=State(true,true,-1);if (l==r) return;State sl=ls->s,sr=rs->s;s.l=sl.l;s.r=sr.r;s.n=sl.n+sr.n+sl.r+sr.l-(sl.r&&sr.l);}void *operator new(size_t,void *p) {return p;}};struct SegTree {Node *root,*cur;Node a[100000];Node *maketree(int l,int r) {Node *ans=new(cur++)Node(l,r);if (l==r) return ans;int t=(l+r)/2;ans->ls=maketree(l,t);ans->rs=maketree(t+1,r);return ans;}void clear(int n) {cur=a;root=maketree(0,n-1);}void print() {for (Node *i=a;i!=cur;i++) {//printf("Node %d: l=%d, r=%d, ls=%d, rs=%d\n",i-a,i->l,i->r,i->ls-a,i->rs-a);//printf("   press=%d state=%d,%d,%d\n",i->times,i->s.l,i->s.r,i->s.n);}}void press(Node *from,int l,int r) {if (from->l==l&&from->r==r) {from->times++;from->update();return;}int t=(from->l+from->r)/2;if (t<l) press(from->rs,l,r);else if (t>=r) press(from->ls,l,r);else {press(from->ls,l,t);press(from->rs,t+1,r);}from->update();}void release(Node *from,int l,int r) {if (from->l==l&&from->r==r) {from->times--;from->update();return;}int t=(from->l+from->r)/2;if (t<l) release(from->rs,l,r);else if (t>=r) release(from->ls,l,r);else {release(from->ls,l,t);release(from->rs,t+1,r);}from->update();}};set <int> c;map <int,int> d;int n,m,p;Opt b[20000];SegTree a;int main() {int t,tt,last,i;scanf("%d",&t);for (tt=1;tt<=t;tt++) {printf("Case #%d:\n",tt);scanf("%d%d",&n,&m);c.clear();d.clear();for (i=0;i<m;i++) {b[i].read();c.insert(b[i].l);c.insert(b[i].r);}p=0;last=-1;for (set<int>::iterator it=c.begin();it!=c.end();it++) {if (*it-1!=last) p++;//printf("tran: %d %d\n",*it,p);d[last=*it]=p++;}if (last!=n-1) p++;a.clear(p);for (i=0;i<m;i++) {if (b[i].p) a.press(a.root,d[b[i].l],d[b[i].r]);else a.release(a.root,d[b[i].l],d[b[i].r]);State tmp=a.root->s;printf("%d\n",tmp.n+tmp.l+tmp.r);//a.print();}}return 0;}


0 0