[SHOI2015]脑洞治疗仪(线段树?珂朵莉树)
Posted hale522520
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SHOI2015]脑洞治疗仪(线段树?珂朵莉树)相关的知识,希望对你有一定的参考价值。
这道题超级可爱呢,珂朵莉最可爱了,不,小哀才是最可爱的呢
很好的题,可以考虑用线段树维护,hale表示线段树思路很难,而且难打,不如滚去写珂朵莉树哦
对于操作一:直接将set修改插入即可
对于操作三:最大连续子段和(线段树里面是这样叫的吧)维护即可
对于操作二:我们发现可以考虑先将这段区间里面的1 全部取出来,然后暴力合并区间为0,插入会set里面
之后枚举要修改的区间,从左端点开始搞起,一直后搜索,最后加一个判断,是否已经完全ok即可,具体可参见代码
好了,这道题就解决了
我的代码好像luogu会RE四个点,莫名其妙,loj就可以直接AC了,开心
#include<bits/stdc++.h> #define IT set<node>::iterator using namespace std; const int N=2e5+7; int m,n; struct node { int l,r; mutable int v; node(int L,int R=-1,int V=0):l(L),r(R),v(V){} bool operator<(const node &x) const { return l<x.l; } }; set<node> s; IT split(int pos) { IT it=s.lower_bound(node(pos)); if (it!=s.end()&&it->l==pos) return it; it--; int L=it->l,R=it->r,V=it->v; s.erase(it); s.insert(node(L,pos-1,V)); return s.insert(node(pos,R,V)).first; } void del(int l,int r) { IT itr=split(r+1),itl=split(l); s.erase(itl,itr); s.insert(node(l,r,0)); } int query(int l,int r) { int ans=0,mx=0; IT itr=split(r+1),itl=split(l); for (;itl!=itr;itl++) if (!itl->v) ans+=itl->r-itl->l+1; else mx=max(mx,ans),ans=0; return max(mx,ans); } void put(int l0,int r0,int l,int r) { IT itr=split(r0+1),itl=split(l0),it=itl; int sum=0; for (;itl!=itr;itl++) if (itl->v) sum+=itl->r-itl->l+1; s.erase(it,itr);s.insert(node(l0,r0,0)); itr=split(r+1);it=itl=split(l); int tot=0; for (;itl!=itr&&tot<sum;itl++) if (!itl->v) tot+=itl->r-itl->l+1; if (itl==itr&&tot<=sum) s.erase(it,itr),s.insert(node(l,r,1)); else { int pos=itl->l+sum-tot-1; IT itp=split(pos+1); s.erase(it,itp); s.insert(node(l,pos,1)); } } int main() { scanf("%d%d",&n,&m); s.insert(node(1,n,1));s.insert(node(n+1,n+1,0)); for (int i=1;i<=m;i++) { int op,l,r; scanf("%d%d%d",&op,&l,&r); if (op==0) del(l,r); if (op==2) printf("%d\n",query(l,r)); if (op==1) { int l0,r0;scanf("%d%d",&l0,&r0); put(l,r,l0,r0); } } return 0; }
以上是关于[SHOI2015]脑洞治疗仪(线段树?珂朵莉树)的主要内容,如果未能解决你的问题,请参考以下文章
Solution: 题解 CF896C Willem, Chtholly and Seniorious(线段树解珂朵莉树)
hdu4578线段树维护平方和,立方和(加,乘,赋值)或者珂朵莉树