[SCOI2010]序列操作 题解报告
本来是一道线段树的好题,结果被ODT(珂朵莉树)暴力+玄学跑过......
不过这也是珂朵莉树新学者的很好的板子题诶
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IT set<node>::iterator
struct node{
int l,r;
mutable int val;
bool operator < (const node &x) const{
return l<x.l;
}
};
set<node>tr;
IT split(int pos)
{
IT iter=tr.lower_bound((node){pos});
if(iter!=tr.end()&&iter->l==pos)
return iter;
iter--;
int nwl=iter->l,nwr=iter->r,nwval=iter->val;
tr.erase(iter);
tr.insert((node){nwl,pos-1,nwval});
return tr.insert((node){pos,nwr,nwval}).first;
}
void assign(int l,int r,int val)
{
IT iter_r=split(r+1),iter_l=split(l);
tr.erase(iter_l,iter_r);
tr.insert((node){l,r,val});
return;
}
void fiu(int l,int r)
{
IT iter_r=split(r+1),iter_l=split(l);
for(;iter_l!=iter_r;++iter_l)
iter_l->val=iter_l->val==1?0:1;
return;
}
int query(int l,int r)
{
IT iter_r=split(r+1),iter_l=split(l);
int ans=0;
for(;iter_l!=iter_r;++iter_l)
ans+=(iter_l->val)*(iter_l->r-iter_l->l+1);
return ans;
}
int QAQ(int l,int r)
{
IT iter_r=split(r+1),iter_l=split(l);
int mx=0,sum=0;
for(;iter_l!=iter_r;++iter_l)
if(iter_l->val==1)
{
int pop=iter_l->r-iter_l->l+1;
sum+=pop;
}
else mx=max(mx,sum),sum=0;
return max(mx,sum);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
int x;
scanf("%d",&x);
tr.insert((node){i,i,x});
}
tr.insert((node){n,n,0});
while(m--)
{
int kkk,a,b;
scanf("%d%d%d",&kkk,&a,&b);
if(kkk==0) assign(a,b,0);
if(kkk==1) assign(a,b,1);
if(kkk==2) fiu(a,b);
if(kkk==3) printf("%d\n",query(a,b));
if(kkk==4) printf("%d\n",QAQ(a,b));
}
return 0;
}
不过如果没有区间赋值这一层操作的话,ODT退化下来还是O(n^2)的吧...
不得不说ODT处理随机数据的复杂度还真是蛮玄学的