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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[luogu2042] [NOI2005]维护数列

發布時間:2024/4/11 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [luogu2042] [NOI2005]维护数列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

寫寫比較麻煩的這題

題目相關

題目大意

寫一個大數據結構

數據范圍

20000
題目鏈接

前置

先過模板題,比如會個非旋treap,寫一下,通過[luogu3369][模板]普通平衡樹
possible version

#include<cstdio> #include<cctype> #include<cmath> #include<algorithm> #include<cstdlib> #include<ctime> #define rg register namespace fast_IO {const int IN_LEN=1000000,OUT_LEN=1000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);} } using namespace fast_IO; #define getchar() getchar_() #define putchar(x) putchar_((x)) typedef long long ll; template<typename T>inline T min(const T x,const T y){return x<y?x:y;} template<typename T>inline T max(const T x,const T y){return x>y?x:y;} template<typename T>inline T abs(const T x){return x>0?x:-x;} template<typename T>inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);} template<typename T>inline void swap(T&a,T&b){const T c=a;a=b;b=c;} template<typename T>inline void read(T&x) {char cu=getchar();bool fla=0;x=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x; } template<typename T>inline void printe(const T x) {if(x>=10)printe(x/10);putchar(x%10+'0'); } template<typename T>inline void print(const T x) {if(x<0)putchar('-'),printe(-x);else printe(x); } const int maxn=500001; struct Point {int x,key,lson,rson,size; }Q[maxn];int usd,root; int newnode(const int v) {usd++;Q[usd]=(Point){v,rand(),0,0,1};return usd; } void update(const int x) {Q[x].size=Q[Q[x].lson].size+Q[Q[x].rson].size+1; } std::pair<int,int> split(const int x,const int v) {std::pair<int,int>res(0,0);if(!x)return res;if(Q[x].x<=v){res=split(Q[x].rson,v);Q[x].rson=res.first;res.first=x;}else{res=split(Q[x].lson,v);Q[x].lson=res.second;res.second=x;}update(x);return res; } int merge(int x,int y) {if(!x)return y;if(!y)return x;if(Q[x].key<Q[y].key){Q[x].rson=merge(Q[x].rson,y);update(x);return x;}else{Q[y].lson=merge(x,Q[y].lson);update(y);return y;} } void insert(const int x) {std::pair<int,int> R=split(root,x);root=merge(merge(R.first,newnode(x)),R.second); } void del(const int x) {std::pair<int,int> R=split(root,x),T=split(R.first,x-1);if(T.second==0)return;root=merge(merge(T.first,merge(Q[T.second].lson,Q[T.second].rson)),R.second); } int rerank(int v) {int x=root,ans=0;while(x){if(Q[x].x<v)ans+=Q[Q[x].lson].size+1,x=Q[x].rson;else x=Q[x].lson;}return ans+1; } int atrank(int rk) {int x=root;while(1){const int all=Q[Q[x].lson].size+1;if(all==rk)return Q[x].x;if(all<rk)x=Q[x].rson,rk-=all;else x=Q[x].lson;} } int prec(int v) {int x=root,ans=0;while(x){if(Q[x].x<v)ans=Q[x].x,x=Q[x].rson;else x=Q[x].lson;}return ans; } int succ(int v) {int x=root,ans=0;while(x){if(Q[x].x>v)ans=Q[x].x,x=Q[x].lson;else x=Q[x].rson;}return ans; } int n; int main() {read(n),srand(time(0));for(rg int i=1;i<=n;i++){int opt,x;read(opt),read(x);if(opt==1)insert(x);else if(opt==2)del(x);else if(opt==3)print(rerank(x)),putchar('\n');else if(opt==4)print(atrank(x)),putchar('\n');else if(opt==5)print(prec(x)),putchar('\n');else print(succ(x)),putchar('\n');}return flush(),0; }

題解

我們發現這里是要維護序列,那么我們需要把split魔改一下,改成“把第1-x個數放到左子樹,其余放到右子樹”

接下來我們考慮操作
首先我們發現初始在treap中的那些數等價于一次insert操作,所以在此不討論
接下來,講述每個操作的做法

  • 插入
    這個操作按一般平衡樹操作就可以了

版本1(代碼已刪除):
我的代碼中把log變成了sort的,rand值直接從上到下填即可

版本2(本文代碼):
構造笛卡爾樹,復雜度變成次數log加上數量了,減小常數

  • 刪除
    直接旋出來那棵樹,不過值得注意的是,需要對節點進行回收,否則空間復雜度受不了
  • 修改
    打個子樹修改標記即可
  • 翻轉
    打個子樹修改標記即可
  • 求和
    記錄子樹權值和即可
  • 求和最大的子列
    記錄子列中最大的子段,最大前綴,最大后綴
    值得注意的是,由于題目所述的區間長度必須大于0,所以要注意負權點的處理

這題看起來非常的簡單,其實在具體實現過程中要注意各個標記之間的影響,需要實現好
另外,注意翻轉標記下傳是翻轉狀態,不然很容易調不出來
code

#include<cstdio> #include<cctype> #include<cmath> #include<algorithm> #include<cstdlib> #include<ctime> #define rg register namespace fast_IO {const int IN_LEN=1000000,OUT_LEN=1000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);} } using namespace fast_IO; #define getchar() getchar_() #define putchar(x) putchar_((x)) typedef long long ll; template<typename T>inline T min(const T x,const T y){return x<y?x:y;} template<typename T>inline T max(const T x,const T y){return x>y?x:y;} template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;} template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;} template<typename T>inline T abs(const T x){return x>0?x:-x;} template<typename T>inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);} template<typename T>inline void swap(T&a,T&b){const T c=a;a=b;b=c;} template<typename T>inline void read(T&x) {char cu=getchar();bool fla=0;x=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x; } template<typename T>inline void printe(const T x) {if(x>=10)printe(x/10);putchar(x%10+'0'); } template<typename T>inline void print(const T x) {if(x<0)putchar('-'),printe(-x);else printe(x); } const int maxn=500001; struct Point//平衡樹節點 {int x,key,lson,rson,size;int zuoda,youda,zhong,he;bool flag;int change; }Q[maxn];int root; void blbl(const int x) {if(!x)return;printf("%d\n",Q[x].x);blbl(Q[x].lson);blbl(Q[x].rson); } int rubbish[maxn],top; int newnode(const int R)//新建節點 傳入rand {int usd=rubbish[top--];Q[usd]=(Point){0,R,0,0,1,0,0,0,0,0,-1001};return usd; } void change(Point&hos,const int x)//改變單點的x {hos.x=x;maxd(hos.zuoda,x),maxd(hos.youda,x);hos.zhong=x;hos.he+=x; } void deal_flag(Point&hos)//解決翻轉 {swap(hos.lson,hos.rson);swap(hos.zuoda,hos.youda);hos.flag^=1; } void deal_change(Point&hos,const int x)//解決賦值 {hos.x=x;if(x>0)hos.zuoda=hos.youda=hos.zhong=hos.he=hos.size*x;else hos.zuoda=hos.youda=0,hos.zhong=x,hos.he=hos.size*x;hos.change=x; } void down(Point&hos)//下傳標記 {int w=hos.lson;if(w){if(hos.flag)deal_flag(Q[w]);if(hos.change!=-1001)deal_change(Q[w],hos.change);}w=hos.rson;if(w){if(hos.flag)deal_flag(Q[w]);if(hos.change!=-1001)deal_change(Q[w],hos.change);}hos.flag=0,hos.change=-1001; } void update(Point&hos)//更新 {Point&L=Q[hos.lson],&R=Q[hos.rson];hos.size=L.size+R.size+1;hos.he=L.he+R.he+hos.x;hos.zuoda=max(L.zuoda,L.he+hos.x+R.zuoda);hos.youda=max(R.youda,R.he+hos.x+L.youda);hos.zhong=max(max(L.zhong,R.zhong),L.youda+hos.x+R.zuoda); } std::pair<int,int> split(const int x,const int kth) {std::pair<int,int>res(0,0);if(!x)return res;down(Q[x]);if(Q[Q[x].lson].size+1==kth){res.first=x,res.second=Q[x].rson;Q[x].rson=0;}else if(Q[Q[x].lson].size+1<kth){res=split(Q[x].rson,kth-(Q[Q[x].lson].size+1));Q[x].rson=res.first;res.first=x;}else{res=split(Q[x].lson,kth);Q[x].lson=res.second;res.second=x;}update(Q[x]);return res; } int merge(int x,int y) {if(!x)return y;if(!y)return x;down(Q[x]),down(Q[y]);if(Q[x].key<Q[y].key){Q[x].rson=merge(Q[x].rson,y);update(Q[x]);return x;}else{Q[y].lson=merge(x,Q[y].lson);update(Q[y]);return y;} } int m,P[maxn],Ptop; char opt[11];int opttop; int STA[maxn],Stop,ID[maxn]; int maker() {int rando=rand();STA[Stop=1]=newnode(rando),ID[Stop]=P[1];for(rg int i=2;i<=Ptop;i++){int ME=newnode(rando);rando=rand();bool fla=0;while(Stop>1&&rando<Q[STA[Stop]].key)Q[STA[Stop-1]].rson=STA[Stop],change(Q[STA[Stop]],ID[Stop]),update(Q[STA[Stop]]),Stop--,fla=1;if(rando<Q[STA[Stop]].key){change(Q[STA[Stop]],ID[Stop]),update(Q[STA[Stop]]);Q[ME].lson=STA[Stop];STA[Stop]=ME,ID[Stop]=P[i];}else{if(fla){Q[STA[Stop]].rson=0;Q[ME].lson=STA[Stop+1];}STA[++Stop]=ME,ID[Stop]=P[i];}}while(Stop>1)Q[STA[Stop-1]].rson=STA[Stop],change(Q[STA[Stop]],ID[Stop]),update(Q[STA[Stop]]),Stop--;change(Q[STA[Stop]],ID[Stop]),update(Q[STA[Stop]]);return STA[1]; } void insert(const int x) {std::pair<int,int>T=split(root,x);root=merge(merge(T.first,maker()),T.second); } void rerubbish(const int x) {if(!x)return;rubbish[++top]=x;rerubbish(Q[x].lson),rerubbish(Q[x].rson); } void del(const int x) {std::pair<int,int>T=split(root,x),S=split(T.second,Ptop);rerubbish(S.first);root=merge(T.first,S.second); } int samv; void sam(const int x) {std::pair<int,int>T=split(root,x),S=split(T.second,Ptop);deal_change(Q[S.first],samv);root=merge(merge(T.first,S.first),S.second); } void reverse(const int x) {std::pair<int,int>T=split(root,x),S=split(T.second,Ptop);deal_flag(Q[S.first]);root=merge(merge(T.first,S.first),S.second); } int sum(const int x)//complete {std::pair<int,int>T=split(root,x),S=split(T.second,Ptop);int res=Q[S.first].he;root=merge(merge(T.first,S.first),S.second);return res; } int bigv(const int x)//compete {return Q[root].zhong; } int main() {Q[0].zhong=-(0x7f7f7f7f);for(rg int i=1;i<=500000;i++)rubbish[++top]=i;read(Ptop),read(m),srand(time(0));for(rg int i=1;i<=Ptop;i++)read(P[i]);insert(0);for(rg int i=1;i<=m;i++){int x;opt[opttop=1]=getchar();while(opt[1]<'A'||opt[1]>'Z')opt[1]=getchar();while(opt[opttop]!=' '&&opt[opttop]!='\n'&&opt[opttop]!=EOF)opt[++opttop]=getchar();if(opt[1]=='I'){read(x),read(Ptop);for(rg int i=1;i<=Ptop;i++)read(P[i]);insert(x);}else if(opt[1]=='D'){read(x),read(Ptop);x--;del(x);} else if(opt[3]=='K'){read(x),read(Ptop),read(samv);x--;sam(x);}else if(opt[1]=='R'){read(x),read(Ptop);x--;reverse(x);}else if(opt[1]=='G'){read(x),read(Ptop);x--;print(sum(x)),putchar('\n');}else print(bigv(root)),putchar('\n');}return flush(),0; }

總結

一道較為繁瑣的數據結構,調了有一會兒,馬上就要csp了,還得加強代碼熟練度

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。