总体思路其实跟用线段树维护区间最大字段和差不多,不过唯一麻烦的地方在于要算上自己。
然后我们可以开一个队列来回收那些被delete的点,这样可以节省空间,特别需要注意的是release的时候,标记什么的一定记得清空。
本来insert我是直接一个个merge的,这样就会导致特别慢,因此我们可以借助笛卡尔树的思想来直接O(n)的建树,最后再merge,这样的话会快非常多。具体来说就是维护一个右链,然后每次加入新的点,如果它的优先级比当前右链底部的点(栈顶)大,那么就直接弹栈。那么最后top的右儿子就是新加的节点,而最后一个弹出的点就是当前点的左儿子。
最后记得将所有点依次退栈,然后每一次退栈,都要相应update,包括上面的。
另外说一点,之所以每次release都要清空标记是因为,用这种O(n)的建树方法是不会考虑到原来的标记的,我原来写的release并没有清除标记,而原来直接merge的时候是会先下传标记,所以不会有问题,这也解释了为什么我只是改变建树的方式会错,因为没有清空标记。
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<queue>
#define fo(i,a,b) for (register int (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (register int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int inf=1e9;
const int N=1e6+5;
int n,m,rt,cnt;
int p[N],ls[N],rs[N],v[N],s[N];
int lm[N],rm[N],sm[N],sum[N];
bool t[N];
int set[N],x,y,k,z,l,r,tot,c[N],u;
int LC,RC;
char ch[20];
queue<int> q;
bool vis[N];
int a[N];
int max(int a,int b){
return a<b ? b:a;
}
void swap(int &a,int &b){
u=a; a=b; b=u;
}
void R(int &x){
int t=0,p=1; char ch;
for (ch=getchar();!('0'<=ch && ch<='9');ch=getchar()) {
if (ch=='-') p=-1;
}
for (;('0'<=ch && ch<='9');ch=getchar()) t=t*10+ch-'0';
x=t*p;
}
inline int New(int x){
cnt=q.front(); q.pop();
p[cnt]=rand();
v[cnt]=x;
ls[cnt]=rs[cnt]=0;
s[cnt]=1;
sum[cnt]=lm[cnt]=rm[cnt]=sm[cnt]=x;
return cnt;
}
void upd(int x){
LC=ls[x];
RC=rs[x];
s[x]=s[LC]+s[RC]+1;
sum[x]=sum[LC]+sum[RC]+v[x];
if (LC) {
lm[x]=max(lm[LC], sum[LC]+v[x]);
lm[x]=max(lm[x], sum[LC]+v[x]+lm[RC]);
}
else{
lm[x]=max(v[x],v[x]+lm[RC]);
}
if (RC) {
rm[x]=max(rm[RC], v[x]+sum[RC]);
rm[x]=max(rm[x], rm[LC]+v[x]+sum[RC]);
}
else{
rm[x]=max(v[x],rm[LC]+v[x]);
}
sm[x]=v[x];
if (LC) {
sm[x]=max(sm[x],sm[LC]);
sm[x]=max(sm[x],rm[LC]+v[x]);
}
if (RC) {
sm[x]=max(sm[x],sm[RC]);
sm[x]=max(sm[x],lm[RC]+v[x]);
}
if (LC && RC) {
sm[x]=max(sm[x],rm[LC]+v[x]+lm[RC]);
}
}
inline void rev(int x){
t[x]^=1;
swap(lm[x],rm[x]);
}
inline void cha(int x,int m){
set[x]=m;
sum[x]=s[x]*m;
v[x]=m;
if (m>0) {
lm[x]=rm[x]=sm[x]=s[x]*m;
}
else{
lm[x]=rm[x]=sm[x]=m;
}
}
void push(int x){
if (set[x]!=inf){
cha(ls[x],set[x]);
cha(rs[x],set[x]);
set[x]=inf;
t[x]=0;//
return;
}
if (t[x]){
swap(ls[x],rs[x]);
rev(ls[x]);
rev(rs[x]);
t[x]=0;
}
}
void split(int u,int x,int &l,int &r){
if (!u) {
l=r=0;
return;
}
push(u);
if (s[ls[u]]+1<=x) {
l=u;
split(rs[u], x-s[ls[u]]-1, rs[u], r);
}
else{
r=u;
split(ls[u], x, l, ls[u]);
}
upd(u);
}
inline int merge(int l,int r){
if (!l || !r) return l+r;
push(l); push(r);
if (p[l]>p[r]) {
rs[l]=merge(rs[l],r);
upd(l);
return l;
}
else{
ls[r]=merge(l,ls[r]);
upd(r);
return r;
}
}
void pf(int x){
if (!x) return;
push(x);
pf(ls[x]);
printf("%d ",v[x]);
pf(rs[x]);
}
inline void W(int x){
if (!x) {
puts("0");
return;
}
if (x<0) {
putchar('-');
x=-x;
}
tot=0;
while (x){
c[++tot]=x%10;
x/=10;
}
fd(i,tot,1) {
putchar(c[i]+'0');
}
putchar('\n');
}
void rel(int x){
if (!x) return;
rel(ls[x]);
set[x]=inf;
t[x]=0;
q.push(x);
rel(rs[x]);
}
int ss[N];
int build(int num)
{
int x = 0;
int last = 0;
int top = 0;
for (int i = 1; i <= num; i ++ )
{
scanf("%d",&k);
x = New(k);
last = 0;
while(top && p[ss[top]] > p[x])
{
upd(ss[top]);
last = ss[top];
ss[top -- ] = 0;
}
if(top)
{
rs[ss[top]] = x;
}
ls[x] = last;
ss[++top] = x;
}
while(top)
upd(ss[top -- ]);
return ss[1];
}
int main(){
fo(i,0,N-1) set[i]=inf;
fo(i,1,5e5+1) q.push(i);
srand(time(NULL));
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
R(n); R(m);
fo(i,1,n) {
R(x);
New(x);
rt=merge(rt,cnt);
}
while (m--) {
scanf("%s",ch);
switch (ch[2]){
case 'S':
z=0;
int temp;
R(x); R(y);
temp=x;
z=build(y);
split(rt,temp,l,r);
rt=merge(l,z);
rt=merge(rt,r);
break;
case 'L':
R(x); R(y);
split(rt,x+y-1,l,r);
split(l,x-1,l,z);
rel(z);
rt=merge(l,r);
break;
case 'K':
R(x); R(y); R(k);
split(rt,x+y-1,l,r);
split(l,x-1,l,z);
cha(z,k);
rt=merge(l,z);
rt=merge(rt,r);
break;
case 'V':
R(x); R(y);
split(rt,x+y-1,l,r);
split(l,x-1,l,z);
rev(z);
rt=merge(l,z);
rt=merge(rt,r);
break;
case 'T':
R(x); R(y);
split(rt,x+y-1,l,r);
split(l,x-1,l,z);
W(sum[z]);
rt=merge(l,z);
rt=merge(rt,r);
break;
case 'X':
W(sm[rt]);
break;
}
}
return 0;
}
完结撒花。
标签:rt,return,数列,int,merge,NOI2005,split,维护,ls From: https://www.cnblogs.com/ganking/p/17361825.html