日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

[NOI2005]维护数列

發(fā)布時間:2023/11/27 生活经验 63 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [NOI2005]维护数列 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

輸入格式

輸入文件的第 1 行包含兩個數(shù) N 和 M,N 表示初始時數(shù)列中數(shù)的個數(shù),M 表示要進行的操作數(shù)目。 第 2 行包含 N 個數(shù)字,描述初始時的數(shù)列。 以下 M 行,每行一條命令,格式參見問題描述中的表格

輸出格式

對于輸入數(shù)據(jù)中的 GET-SUM 和 MAX-SUM 操作,向輸出文件依次打印結(jié) 果,每個答案(數(shù)字)占一行。

你可以認為在任何時刻,數(shù)列中至少有 1 個數(shù)。

輸入數(shù)據(jù)一定是正確的,即指定位置的數(shù)在數(shù)列中一定存在。

100%的數(shù)據(jù)中,任何時刻數(shù)列中最多含有 500 000 個數(shù)。

100%的數(shù)據(jù)中,任何時刻數(shù)列中任何一個數(shù)字均在[-1 000, 1 000]內(nèi)。

100%的數(shù)據(jù)中,M ≤20 000,插入的數(shù)字總數(shù)不超過 4 000 000 。

題解

序列翻轉(zhuǎn)基本操作

區(qū)間最大子段和

有了上面的鋪墊,其實這些操作都可以解決了。

以下的根不做特殊說明都指區(qū)間代表子樹的根。

只是有點小細節(jié)需要注意:

插入時要先把插入序列建splay,不然一個一個插入會超時。建splay時需要特判葉子節(jié)點維護一些信息,對于lmax和rmax需要將val和0取max,因為在父親節(jié)點更新lmax是可能為左區(qū)間+父親節(jié)點本身,如果右區(qū)間lmax直接取val,就可能取不到這種情況,或許比較三種情況可以解決這個問題,但是很麻煩不是嗎。

刪除的時候,把這段區(qū)間提取出來刪除即可。不過因為空間原因需要回收節(jié)點編號,所以需要遍歷這棵子樹回收,用隊列裝編號。最多插入4e6個數(shù),所以最多遍歷4e6個點。

區(qū)間覆蓋的時候,提取區(qū)間后,在根打上覆蓋標(biāo)記,維護節(jié)點信息:注意如果val是負數(shù)最大子段和賦成val。

翻轉(zhuǎn)提取區(qū)間,在根打上翻轉(zhuǎn)標(biāo)記,將lmax和rmax交換

求和提取區(qū)間輸出根的sum即可。

這道題的最大子段和是整個序列的,其實降低了一點難度,直接輸出整顆splay的根的最大子段和即可。

下傳在find里面。

建初始序列時要在收尾插入兩個最小值,因為最大值在求最大子段和會有影響。

還有對于0號節(jié)點的最大子段和賦最小值,因為一些沒有兒子的點更新信息會用到。

#include<bits/stdc++.h>
using namespace std;#define ll long long
const ll oo=1000000;
const int maxn=500005;
int n,m;
ll a[maxn],num,id[maxn],root;
queue<int> q;
struct Splay{int s[2],fa,size,tag,cover;//tag:當(dāng)前節(jié)點是否需要交換兒子
  ll val,sum,dat,lmax,rmax;
}tr[maxn];template<class T>inline void read(T &x){x=0;int f=0;char ch=getchar();while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}x= f ? -x : x ;
}ll max(ll x,ll y){return x>y ? x : y ;}void update(Splay &ret,Splay lx,Splay ry){ret.size=lx.size+ry.size+1;ret.sum=lx.sum+ry.sum+ret.val;ret.lmax=max(lx.lmax,lx.sum+ret.val+ry.lmax);ret.rmax=max(ry.rmax,ry.sum+ret.val+lx.rmax);ret.dat=max(max(lx.dat,ry.dat),lx.rmax+ret.val+ry.lmax);//給0賦值防止了出事//printf("-%d-",ret.val);
}void update(int x){update(tr[x],tr[tr[x].s[0]],tr[tr[x].s[1]]);
}int build(int l,int r,int f){//printf("%d %d\n",l,r);if(l>r) return 0;int mid=(l+r)>>1,now=id[mid];tr[now].fa=f;tr[now].val=a[mid];tr[now].cover=oo;if(l==r){tr[now].size=1;tr[now].sum=tr[now].val;tr[now].lmax=tr[now].rmax=max(0,tr[now].val);tr[now].dat=tr[now].val;//記得賦值return now;}tr[now].s[0]=build(l,mid-1,now);tr[now].s[1]=build(mid+1,r,now);update(now);return now;
}void put_cover(int x,ll val){if(!x) return ;tr[x].val=tr[x].cover=val;tr[x].sum=val*tr[x].size;tr[x].lmax=tr[x].rmax= val>=0 ? tr[x].sum : 0;tr[x].dat= val>=0 ? tr[x].sum : val;//必須選取至少一個元素
}void put_tag(int x){if(!x) return ;tr[x].tag^=1;swap(tr[x].s[0],tr[x].s[1]);swap(tr[x].lmax,tr[x].rmax);
}void push_down(int x){if(tr[x].cover!=oo){put_cover(tr[x].s[0],tr[x].cover);put_cover(tr[x].s[1],tr[x].cover);tr[x].cover=oo;}if(tr[x].tag){put_tag(tr[x].s[0]);put_tag(tr[x].s[1]);tr[x].tag=0;}
}void debug(int x){push_down(x);if(tr[x].s[0]) debug(tr[x].s[0]);printf("%lld ",tr[x].val);if(tr[x].s[1]) debug(tr[x].s[1]);
}int find(int k){int now=root;while(1){//printf("%d %d\n",k,now);
    push_down(now);if(tr[tr[now].s[0]].size>=k) {now=tr[now].s[0];continue;}k-=tr[tr[now].s[0]].size;if(k==1) return now;k--;now=tr[now].s[1];}
}int get(int x){return tr[tr[x].fa].s[1]==x;
}void connect(int x,int y,int d){tr[y].s[d]=x;tr[x].fa=y;
}void rotate(int x){int f=tr[x].fa,ff=tr[f].fa;int d1=get(x),d2=get(f);int cs=tr[x].s[d1^1];connect(x,ff,d2);connect(f,x,d1^1);connect(cs,f,d1);update(f);update(x);
}void splay(int x,int go){if(go==root) root=x;go=tr[go].fa;while(tr[x].fa!=go){int f=tr[x].fa;if(tr[f].fa==go) rotate(x);else if(get(x)==get(f)) {rotate(f);rotate(x);}else {rotate(x);rotate(x);}}
}void insert(){int pos,tot;read(pos);read(tot);n+=tot;for(int i=1;i<=tot;i++){read(a[i]);if(!q.empty()) id[i]=q.front(),q.pop();else id[i]=++num;}int nowroot=build(1,tot,0);int x=find(pos+1),y=find(pos+2);splay(x,root);splay(y,tr[x].s[1]);tr[nowroot].fa=y;tr[y].s[0]=nowroot;update(y);update(x);
}void clean(int x){tr[x]=(Splay){{0,0},0,0,0,oo,0,0,0,0,0};
}void recycle(int x){if(tr[x].s[0]) recycle(tr[x].s[0]);if(tr[x].s[1]) recycle(tr[x].s[1]);clean(x);q.push(x);
}void dele(){int pos,tot;read(pos);read(tot);n-=tot;int x=find(pos),y=find(pos+tot+1);splay(x,root);splay(y,tr[x].s[1]);recycle(tr[y].s[0]);tr[y].s[0]=0;update(y);update(x);
}void modify(){int pos,tot;ll val;read(pos);read(tot);read(val);int x=find(pos),y=find(pos+tot+1);splay(x,root);splay(y,tr[x].s[1]);put_cover(tr[y].s[0],val);update(y);update(x);
}void reverse(){int pos,tot;read(pos);read(tot);int x=find(pos),y=find(pos+tot+1);splay(x,root);splay(y,tr[x].s[1]);put_tag(tr[y].s[0]);update(y);update(x);
}ll querysum(){int pos,tot;read(pos);read(tot);int x=find(pos),y=find(pos+tot+1);splay(x,root);splay(y,tr[x].s[1]);//printf("%d %d\n",x,y);//printf("%d\n",tr[tr[y].s[0]].size);//putchar(10);//debug(tr[y].s[0]);//putchar(10);return tr[tr[y].s[0]].sum;
}ll querydat(){int x=find(1),y=find(n);splay(x,root);splay(y,tr[x].s[1]);return tr[tr[y].s[0]].dat;
}int main(){read(n);read(m);tr[0].dat=a[1]=a[n+2]=-oo;//給零賦值,不然建樹會出鍋for(int i=1;i<=n;i++) read(a[i+1]);for(int i=1;i<=n+2;i++) id[i]=++num;n=n+2;root=build(1,n,0);for(int i=1;i<=m;i++){char opt[15];scanf("%s",opt);if(opt[2]=='S') insert();else if(opt[2]=='L') dele();else if(opt[2]=='K') modify();else if(opt[2]=='V') reverse();else if(opt[2]=='T') printf("%lld\n",querysum());else printf("%lld\n",tr[root].dat);//putchar(10);//debug(root);//putchar(10);
  }
}
View Code

?

轉(zhuǎn)載于:https://www.cnblogs.com/sto324/p/11297521.html

總結(jié)

以上是生活随笔為你收集整理的[NOI2005]维护数列的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。