CF915E Physical Education Lessons(动态开点线段树/珂朵莉树)

H0ndomach1·2022-09-13 16:20·78 次阅读

CF915E Physical Education Lessons(动态开点线段树/珂朵莉树)

CF915E

洛谷链接

题目大意(懒狗直接偷的题面):#

从现在到学期结束还有 n 天(从 1n 编号),他们一开始都是工作日。接下来学校的工作人员会依次发出 q 个指令,每个指令可以用三个参数 l,r,k 描述:

  • 如果 k=1,那么从 lr (包含端点)的所有日子都变成工作日。
  • 如果 k=2,那么从 lr (包含端点)的所有日子都变成工作日
    统计每个指令下发后,剩余的工作日天数。

输入格式:#

第一行一个整数 n,第二行一个整数 q (1n109,1q3105),分别是剩余的天数和指令的个数。

接下来 q 行,第 i 行有 3 个整数 li,ri,ki,描述第 i 个指令 (1li,rin,1k2)

输出格式:#

输出 q 行,第 i 行表示第 i 个指令被下发后剩余的工作日天数。

样例输入 #1#

Copy
4 6 1 2 1 3 4 1 2 3 2 1 3 2 2 4 1 1 4 2

样例输出 #1#

Copy
2 0 2 3 1 4

分析1:#

看到这题会想到常规线段树区间覆盖,但是发现数据范围 n109,线段树需要开四倍空间会超出空间限制。
虽然如此,询问操作还是比较小的,说明提前建好的线段树某些区间几乎用不到,所以可利用动态开点,需要用到此区间的时候再将它建立。

代码1(线段树动态开点):#

Copy
#include<bits/stdc++.h> using namespace std; const int MAXN = 16e6+10; inline int read() { char ch=getchar(); int f=1,x=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return f*x; } int n,m,root=0; int cnt; struct T{ int l,r,val,lazy; }t[MAXN]; int newnode(){ cnt++; t[cnt].lazy=-1; return cnt; } void update(int p){ t[p].val=t[t[p].l].val+t[t[p].r].val; } void pushdown(int l,int r,int p){ if(l==r||t[p].lazy==-1){ return; } if(!t[p].l){ t[p].l=newnode(); } if(!t[p].r){ t[p].r=newnode(); } int mid=(l+r)>>1; t[t[p].l].val=(mid-l+1)*t[p].lazy; t[t[p].r].val=(r-mid)*t[p].lazy; t[t[p].l].lazy=t[p].lazy; t[t[p].r].lazy=t[p].lazy; t[p].lazy=-1; } void change(int l,int r,int &p,int x,int y,int k){ if(r<x||y<l) { return ; } if(!p) p=newnode(); if(x<=l&&r<=y){ t[p].lazy=k; t[p].val=(r-l+1)*k; return; } pushdown(l,r,p); int mid=(l+r)>>1; change(l,mid,t[p].l,x,y,k); change(mid+1,r,t[p].r,x,y,k); //update(p); t[p].val=t[t[p].l].val+t[t[p].r].val; } signed main(){ n=read(); m=read(); change(1,n,root,1,n,1); for(int i=1;i<=m;i++){ int l,r,op; l=read(); r=read(); op=read(); if(op==1){ change(1,n,root,l,r,0); } else{ change(1,n,root,l,r,1); } printf("%d\n",t[1].val); } return 0; }

代码1参考
线段树动态开点教学

分析2:#

区间01赋值操作就是珂朵莉树的常规操作。
所以使用珂朵莉树就是一个较为模板的题。

代码2(珂朵莉树):#

Copy
#include<bits/stdc++.h> #define ll long long #define sit set<asd>::iterator using namespace std; inline ll read() { ll x = 0, fh = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') fh = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } return x * fh; } struct asd{ ll l,r; mutable ll val; bool operator < (const asd& A)const{return l<A.l;} asd(ll aa,ll bb,ll cc){l=aa,r=bb,val=cc;} asd(ll aa){l=aa;} }; int sum=0; ll n,m,maxn,seed; set<asd>s; sit split(ll wz){ sit it=s.lower_bound(asd(wz)); if(it!=s.end()&&it->l==wz)return it; it--; ll l=it->l; ll r=it->r; ll val=it->val; s.erase(it); s.insert(asd(l,wz-1,val)); return s.insert(asd(wz,r,val)).first; } void assign(int l,int r,bool val){ sit itr = split(r+1), itl = split(l), it = itl; for( ;itl != itr; ++itl) sum-=itl->val*(itl->r-itl->l+1); s.erase(it,itr); s.insert(asd(l,r,val)); sum+=val*(r-l+1); } signed main(){ n=read(); m=read(); s.insert(asd(1,n,1)); sum=n; while(m--){ int l=read(),r=read(),op=read(); if(op==1){ assign(l,r,0); } else { assign(l,r,1); } printf("%d\n",sum); } return 0; }

珂朵莉树做法参考

posted @   DAIANZE  阅读(78)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
目录