BZOJ1895: Pku3580 supermemo Splay
生活随笔
收集整理的這篇文章主要介紹了
BZOJ1895: Pku3580 supermemo Splay
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
BZOJ1895: Pku3580 supermemo
Time Limit:?15 Sec??Memory Limit:?64 MB Submit:?291??Solved:?119 [Submit][Status][Discuss] 題解: Splay裸題 關于REVOLVE操作,不難想其實是一個區間平移操作 區間平移操作我是這樣寫的: 先把T模一下區間長度,防止它轉回來。 這樣相當于把后面的T(取模后的)個數字,挪到區間的前面來 這樣先把[r-T+1,r]旋轉出來,然后記一下區間在樹上最上面的點,把它和父親斷開,把父親Pushup,然后在旋轉出[l,l-1],把剛才記的節點和他連上就OK,再Pushup一下上面的點 #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; const int N=200005; int n,m,root,ls[N],rs[N],fa[N],siz[N],mn[N],rev[N],plu[N],a[N],cnt; void Pushup(int x) {siz[x]=siz[ls[x]]+siz[rs[x]]+1;mn[x]=min(a[x],min(mn[ls[x]],mn[rs[x]])); } void Pplu(int x,int v) {if(!x) return;a[x]+=v;mn[x]+=v;plu[x]+=v; } void Prev(int x) {if(!x) return;swap(ls[x],rs[x]);rev[x]^=1; } void Pushdown(int x) {if(plu[x]){Pplu(ls[x],plu[x]),Pplu(rs[x],plu[x]);plu[x]=0;}if(rev[x]){Prev(ls[x]),Prev(rs[x]);rev[x]=0;} } void Rotate(int x,int &k) {int y=fa[x],z=fa[y];if(k==y) k=x;else{if(ls[z]==y) ls[z]=x;else rs[z]=x;}fa[x]=z;fa[y]=x;if(x==ls[y]){ls[y]=rs[x];fa[rs[x]]=y;rs[x]=y;}else{rs[y]=ls[x];fa[ls[x]]=y;ls[x]=y;}Pushup(y);Pushup(x); } void Splay(int x,int &k) {while(x!=k){int y=fa[x],z=fa[y];if(y!=k){if(y==ls[z]^x==ls[y]) Rotate(x,k);else Rotate(y,k);}Rotate(x,k);} } int Find(int x,int rank) {Pushdown(x);if(rank<=siz[ls[x]]) return Find(ls[x],rank);else if(rank==siz[ls[x]]+1) return x;else return Find(rs[x],rank-siz[ls[x]]-1); } int Make(int x,int y) {x=Find(root,x),y=Find(root,y+2);Splay(x,root);Splay(y,rs[x]);return ls[y]; } void Build(int l,int r,int f) {if(l>r) return;if(l==r){siz[l]=1;mn[l]=a[l];fa[l]=f;if(l<f) ls[f]=l;else rs[f]=l;}int mid=(l+r)>>1;Build(l,mid-1,mid);Build(mid+1,r,mid);Pushup(mid);fa[mid]=f;if(mid<f) ls[f]=mid;else rs[f]=mid; } int l,r,x,y,v; void Add() {scanf("%d%d%d",&l,&r,&v);x=Make(l,r);Pplu(x,v); } void Insert() {scanf("%d%d",&l,&v);x=Find(root,l+1),y=Find(root,l+2);Splay(x,root);Splay(y,rs[x]);ls[y]=++cnt;fa[cnt]=y;siz[cnt]=1;a[cnt]=v;mn[cnt]=v;Pushup(y); } void Delete() {scanf("%d",&l);x=Make(l,l);ls[fa[x]]=0;Pushup(fa[x]); } void Min() {scanf("%d%d",&l,&r);x=Make(l,r);printf("%d\n",mn[x]); } void Reverse() {scanf("%d%d",&l,&r);x=Make(l,r);Prev(x); } void Revolve() {scanf("%d%d%d",&l,&r,&v);v%=(r-l+1);if(v==0) return;int p=Make(r-v+1,r);ls[fa[p]]=0;Pushup(fa[p]);x=Find(root,l),y=Find(root,l+1);Splay(x,root);Splay(y,rs[x]);ls[y]=p;fa[p]=y;Pushup(y); } int main() {scanf("%d",&n);memset(mn,0x3f,sizeof(mn));memset(a,0x3f,sizeof(a));for(int i=2;i<=n+1;i++) scanf("%d",&a[i]);root=(n+3)>>1;Build(1,n+2,0);cnt=n+2;scanf("%d",&m);char c[10];while(m--){scanf("%s",c);if(c[0]=='A') Add();else if(c[0]=='I') Insert();else if(c[0]=='D') Delete();else if(c[0]=='M') Min();else if(c[3]=='E') Reverse();else Revolve();} }Description
給出一個初始序列fA1;A2;:::Ang,要求你編寫程序支持如下操作: 1. ADDxyD:給子序列fAx:::Ayg的每個元素都加上D。例如對f1,2, 3,4,5g執行"ADD 241" 會得到f1,3,4,5,5g。 2. REVERSExy:將子序列fAx:::Ayg翻轉。例如對f1,2,3,4,5g執 行"REVERSE 24"會得到f1,4,3,2,5g。 3. REVOLVExyT:將子序列fAx:::Ayg旋轉T個單位。例如, 對f1,2,3,4,5g執行"REVOLVE 242"會得到f1,3,4,2,5g。 4. INSERTxP:在Ax后插入P。例如,對f1,2,3,4,5g執行"INSERT 24"會得到f1,2,4,3,4,5g。 5. DELETEx:刪去Ax。例如,對f1,2,3,4,5g執行"DELETE 2"會得 到f1,3,4,5g。 6. MINxy:查詢子序列fAx:::Ayg中的最小元素。例如,對于序列f1, 2,3,4,5g,詢問"MIN 24"的返回應為2。Input
第一行包含一個整數n,表示初始序列的長度。 以下n行每行包含一個整數,描述初始的序列。 接下來一行包含一個整數m,表示操作的數目。 以下m行每行描述一個操作。Output
對于所有"MIN"操作,輸出正確的答案,每行一個。Sample Input
51
2
3
4
5
2
ADD 2 4 1
MIN 4 5
Sample Output
5HINT
輸入、輸出以及中間運算結果均不會超過32位整數。
對于30%的數據,n;m 6 1000;
對于100%的數據,n;m 6 100000。
Source
[Submit][Status][Discuss]
總結
以上是生活随笔為你收集整理的BZOJ1895: Pku3580 supermemo Splay的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机网络的结构有,计算机网络的组成部分
- 下一篇: mysql order优化2019_My