有一个神奇的机器,它由一排按键构成,在这种机器上有两种操作,第一种是同时按下[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;
}