CF915E Physical Education Lessons
CF915E Physical Education Lessons
Alex高中毕业了,他现在是大学新生。虽然他学习编程,但他还是要上体育课,这对他来说完全是一个意外。快要期末了,但是不幸的Alex的体育学分还是零蛋!
Alex可不希望被开除,他想知道到期末还有多少天的工作日,这样他就能在这些日子里修体育学分。但是在这里计算工作日可不是件容易的事情:
从现在到学期结束还有 $n$ 天(从 $1$ 到 $n$ 编号),他们一开始都是工作日。接下来学校的工作人员会依次发出 $q$ 个指令,每个指令可以用三个参数 $l,r,k$ 描述:
如果 $k=1$,那么从 $l$ 到 $r$ (包含端点)的所有日子都变成非工作日。
如果 $k=2$,那么从 $l$ 到 $r$ (包含端点)的所有日子都变成工作日。
帮助Alex统计每个指令下发后,剩余的工作日天数。
动态开点线段树模板题,又是一道水题
数据范围,又是熟悉的$1≤n≤10^9,1≤q≤3\times10^5$
动态开点线段树啦
调了半天,第$17$个点MLE,why?只好抄了篇不用指针写的版本
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; int n,q; struct node { int f,sum; node *lc,*rc; node() { sum=0,f=0,lc=rc=NULL; } void push_down(int l,int r) { if(!f) return; if(!lc) lc=new node(); if(!rc) rc=new node(); f--; int mid=(l+r)>>1; lc->f=f+1,rc->f=f+1; lc->sum=(mid-l+1)*f; rc->sum=(r-mid)*f; f=0; } void push_up(){ sum=0; if(lc) sum+=lc->sum; if(rc) sum+=rc->sum; } }*root=new node(); void insert(node *&cur){ if(!cur) cur=new node(); } void change(node *&cur,int l,int r,int ql,int qr,int val){ if(!cur) cur=new node(); if(l>=ql&&r<=qr) {cur->sum=(r-l+1)*val;cur->f=val+1;return;} cur->push_down(l,r); int mid=(l+r)>>1; if(qr<=mid) change(cur->lc,l,mid,ql,qr,val),insert(cur->rc); else if(ql>mid) change(cur->rc,mid+1,r,ql,qr,val),insert(cur->lc); else change(cur->lc,l,mid,ql,qr,val),change(cur->rc,mid+1,r,ql,qr,val); cur->push_up(); } int main() { scanf("%d%d",&n,&q); root->sum=0; for(int l,r,k,i=1; i<=q; i++) { scanf("%d%d%d",&l,&r,&k); if(k==2) k=0; change(root,1,n,l,r,k); printf("%d\n",n-root->sum); } return 0; }
敲好用
#include<bits/stdc++.h> #define N 300000 using namespace std; int n,q,tot,v[N*50],lson[N*50],rson[N*50],f[N*50],rt; void insert(int &k){ if(!k) { k=++tot; v[k]=0; } } void push_up(int k){ v[k]=v[lson[k]]+v[rson[k]]; } void push_down(int k,int l,int r){ if(!f[k]) return; if(!lson[k]) lson[k]=++tot; if(!rson[k]) rson[k]=++tot; int mid=(l+r)>>1; --f[k]; v[lson[k]]=(mid-l+1)*f[k]; v[rson[k]]=(r-mid)*f[k]; f[lson[k]]=f[k]+1; f[rson[k]]=f[k]+1; f[k]=0; } void insert(int &k,int l,int r,int ql,int qr,int val){ if(!k) k=++tot; if(l>=ql&&r<=qr) {v[k]=(r-l+1)*val,f[k]=val+1;return;} push_down(k,l,r); int mid=(l+r)>>1; if(ql>mid) insert(rson[k],mid+1,r,ql,qr,val),insert(lson[k]); else if(qr<=mid) insert(lson[k],l,mid,ql,qr,val),insert(rson[k]); else insert(lson[k],l,mid,ql,qr,val),insert(rson[k],mid+1,r,ql,qr,val); push_up(k); } int main() { scanf("%d%d",&n,&q); rt=tot=1; for(int l,r,k,i=1; i<=q; i++) { scanf("%d%d%d",&l,&r,&k); if(k==2) k=0; insert(rt,1,n,l,r,k); printf("%d\n",n-v[rt]); } return 0; }
由数组版的启发,写出了$AC$的指针版
虽然只是改动了赋新地址的方法而已,但是以后还是用这种方法吧,免得出麻烦
#include<bits/stdc++.h> #define N 300000 using namespace std; int n,q,tot; struct node { int f,sum; node *lc,*rc; }*root,x[N*50]; void push_down(node *cur,int l,int r) { if(!cur->f) return; if(!cur->lc) cur->lc=&x[++tot]; if(!cur->rc) cur->rc=&x[++tot]; cur->f--; int mid=(l+r)>>1; cur->lc->f=cur->f+1,cur->rc->f=cur->f+1; cur->lc->sum=(mid-l+1)*cur->f; cur->rc->sum=(r-mid)*cur->f; cur->f=0; } void push_up(node *cur){ cur->sum=0; if(cur->lc) cur->sum+=cur->lc->sum; if(cur->rc) cur->sum+=cur->rc->sum; } void insert(node *&cur){ if(!cur) cur=&x[++tot]; } void change(node *&cur,int l,int r,int ql,int qr,int val){ if(!cur) cur=&x[++tot]; if(l>=ql&&r<=qr) {cur->sum=(r-l+1)*val;cur->f=val+1;return;} push_down(cur,l,r); int mid=(l+r)>>1; if(qr<=mid) change(cur->lc,l,mid,ql,qr,val),insert(cur->rc); else if(ql>mid) change(cur->rc,mid+1,r,ql,qr,val),insert(cur->lc); else change(cur->lc,l,mid,ql,qr,val),change(cur->rc,mid+1,r,ql,qr,val); push_up(cur); } int main() { scanf("%d%d",&n,&q); root=&x[++tot]; for(int l,r,k,i=1; i<=q; i++) { scanf("%d%d%d",&l,&r,&k); if(k==2) k=0; change(root,1,n,l,r,k); printf("%d\n",n-root->sum); } return 0; }
博主蒟蒻,若有出错的地方,敬请指出。
如有侵犯您版权的地方,请快速联系我,我会撤回本博文。