題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2333php
稍微複雜,參考了博客:http://hzwer.com/5780.htmlhtml
用 set 維護全局的最大值就能夠方便地刪除和查詢了;ios
大概就是寫一堆關於可並堆的子函數吧;數組
這裏還用了斜堆,但其實並不明白緣由是什麼...函數
斜堆和左偏樹只有一點點不一樣,它不用 dis ,而是每次都交換左右兒子,隨機地保證了複雜度?spa
要注意 solvetag 函數是要把跟 x 有關的全部 lzy 關係都處理掉,因此也要處理 x 到其兒子的;code
還有 del 處的順序,當心不要讓 set 查詢的東西爲空。htm
代碼以下:blog
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> using namespace std; int const maxn=3e5+5; int n,m,a[maxn],ls[maxn],rs[maxn],fa[maxn],lzy[maxn],ad,sta[maxn],top; multiset<int>st; char ch[5]; int find(int x){while(fa[x])x=fa[x]; return x;} void pushdown(int x) { if(!lzy[x])return; if(ls[x])lzy[ls[x]]+=lzy[x],a[ls[x]]+=lzy[x]; if(rs[x])lzy[rs[x]]+=lzy[x],a[rs[x]]+=lzy[x]; lzy[x]=0; } int merge(int x,int y) { if(!x||!y)return x+y; if(a[x]<a[y])swap(x,y); pushdown(x); rs[x]=merge(rs[x],y); fa[rs[x]]=x; swap(ls[x],rs[x]); return x; } void solvetag(int x) { // x=fa[x]; //從 x 開始,使 x 對兒子沒有 lzy 的關聯 while(x)sta[++top]=x,x=fa[x]; while(top)pushdown(sta[top]),top--; } int del(int x) { solvetag(x); int f=fa[x],k=merge(ls[x],rs[x]); ls[x]=rs[x]=fa[x]=0; fa[k]=f; if(ls[f]==x)ls[f]=k; else rs[f]=k; return find(k); } int rd() { int ret=0,f=1; char cc=getchar(); while(cc<'0'||cc>'9'){if(cc=='-')f=-1; cc=getchar();} while(cc>='0'&&cc<='9')ret=(ret<<3)+(ret<<1)+cc-'0',cc=getchar(); return ret*f; } int main() { n=rd(); for(int i=1;i<=n;i++)a[i]=rd(),st.insert(a[i]); m=rd(); for(int i=1,x,y;i<=m;i++) { cin>>ch; if(ch[0]=='U') { x=rd(); y=rd(); x=find(x); y=find(y); if(x==y)continue;// if(merge(x,y)==x)st.erase(st.find(a[y])); else st.erase(st.find(a[x])); } if(ch[0]=='A'&&ch[1]=='1') { x=rd(); y=rd(); solvetag(x); // int u=del(x); a[x]+=y; // st.erase(st.find(a[u])); //若是 x 只有本身,則刪除後爲空! 則RE // st.insert(a[merge(u,x)]); st.erase(st.find(a[find(x)])); a[x]+=y; st.insert(a[merge(x,del(x))]); } if(ch[0]=='A'&&ch[1]=='2') { x=rd(); y=rd(); int u=find(x); lzy[u]+=y; a[u]+=y; st.erase(st.find(a[u]-y)); st.insert(a[u]); } if(ch[0]=='A'&&ch[1]=='3')y=rd(),ad+=y; if(ch[0]=='F'&&ch[1]=='1')x=rd(),solvetag(x),printf("%d\n",a[x]+ad); if(ch[0]=='F'&&ch[1]=='2')x=rd(),printf("%d\n",a[find(x)]+ad); if(ch[0]=='F'&&ch[1]=='3')printf("%d\n",*(--st.end())+ad); } return 0; }
可是左偏樹也能夠作,並且也許是 set 常數太大,兩種作法用時相差無幾(都很慢,5000ms+);ci
不過比斜堆多開了一個數組呢。
代碼以下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> using namespace std; int const maxn=3e5+5; int n,m,a[maxn],ls[maxn],rs[maxn],fa[maxn],lzy[maxn],ad,sta[maxn],top,dis[maxn]; multiset<int>st; char ch[5]; int find(int x){while(fa[x])x=fa[x]; return x;} void pushdown(int x) { if(!lzy[x])return; if(ls[x])lzy[ls[x]]+=lzy[x],a[ls[x]]+=lzy[x]; if(rs[x])lzy[rs[x]]+=lzy[x],a[rs[x]]+=lzy[x]; lzy[x]=0; } int merge(int x,int y) { if(!x||!y)return x+y; if(a[x]<a[y])swap(x,y); pushdown(x); rs[x]=merge(rs[x],y); fa[rs[x]]=x; if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]); if(rs[x])dis[x]=dis[rs[x]]+1; else dis[x]=0; return x; } void solvetag(int x) { // x=fa[x]; //從 x 開始,使 x 對兒子沒有 lzy 的關聯 while(x)sta[++top]=x,x=fa[x]; while(top)pushdown(sta[top]),top--; } int del(int x) { solvetag(x); int f=fa[x],k=merge(ls[x],rs[x]); ls[x]=rs[x]=fa[x]=dis[x]=0; fa[k]=f; if(ls[f]==x)ls[f]=k; else rs[f]=k; return find(k); } int rd() { int ret=0,f=1; char cc=getchar(); while(cc<'0'||cc>'9'){if(cc=='-')f=-1; cc=getchar();} while(cc>='0'&&cc<='9')ret=(ret<<3)+(ret<<1)+cc-'0',cc=getchar(); return ret*f; } int main() { n=rd(); for(int i=1;i<=n;i++)a[i]=rd(),st.insert(a[i]); m=rd(); for(int i=1,x,y;i<=m;i++) { cin>>ch; if(ch[0]=='U') { x=rd(); y=rd(); x=find(x); y=find(y); if(x==y)continue;// if(merge(x,y)==x)st.erase(st.find(a[y])); else st.erase(st.find(a[x])); } if(ch[0]=='A'&&ch[1]=='1') { x=rd(); y=rd(); solvetag(x); // int u=del(x); a[x]+=y; // st.erase(st.find(a[u])); //若是 x 只有本身,則刪除後爲空! 則RE // st.insert(a[merge(u,x)]); st.erase(st.find(a[find(x)])); a[x]+=y; st.insert(a[merge(x,del(x))]); } if(ch[0]=='A'&&ch[1]=='2') { x=rd(); y=rd(); int u=find(x); lzy[u]+=y; a[u]+=y; st.erase(st.find(a[u]-y)); st.insert(a[u]); } if(ch[0]=='A'&&ch[1]=='3')y=rd(),ad+=y; if(ch[0]=='F'&&ch[1]=='1')x=rd(),solvetag(x),printf("%d\n",a[x]+ad); if(ch[0]=='F'&&ch[1]=='2')x=rd(),printf("%d\n",a[find(x)]+ad); if(ch[0]=='F'&&ch[1]=='3')printf("%d\n",*(--st.end())+ad); } return 0; }