可並堆
阿新 • • 發佈:2018-05-27
線段樹合並 define http har nod namespace 復雜度 scan The
可並堆
可並堆,又稱為左偏樹,滿足從一個節點一直向左兒子走比一直向右兒子走距離更長。
這樣,它就滿足了log層,也就是每次合並的時間復雜度為O(log)
合並:將一個合並到另一個的右兒子上,合並的同時滿足堆的所有性質。
BZOJ1455羅馬遊戲:
維護小根堆,每次合並的時候講大的合並到小的的右兒子上。
可並堆例題,沒有什麽多說的,權值線段樹合並應該也可以做。
附上代碼:
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <iostream> #include <queue> #include <cstdlib> using namespace std; #define N 1000005 int fa[N],n,Q; char s[2]; struct node { int ls,rs,x,dis; }mp[N]; int merge(int x,int y) { if(!x)return y; if(!y)return x; if(mp[x].x>mp[y].x)swap(x,y); mp[x].rs=merge(mp[x].rs,y); if(mp[mp[x].ls].dis<mp[mp[x].rs].dis)swap(mp[x].ls,mp[x].rs); mp[x].dis=mp[mp[x].rs].dis+1; return x; } int find(int x) { if(fa[x]==x)return x; return fa[x]=find(fa[x]); } bool vis[N]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { fa[i]=i; scanf("%d",&mp[i].x); } scanf("%d",&Q); while(Q--) { int x,y; scanf("%s%d",s,&x); if(s[0]==‘M‘) { scanf("%d",&y); if(vis[x]||vis[y])continue; int fx=find(x),fy=find(y); if(fx==fy)continue; fa[fx]=fa[fy]=merge(fx,fy); }else { if(vis[x]) { printf("0\n"); continue; } int fx=find(x); printf("%d\n",mp[fx].x); fa[fx]=fa[mp[fx].ls]=fa[mp[fx].rs]=merge(mp[fx].ls,mp[fx].rs); mp[fx].rs=mp[fx].ls=0; vis[fx]=1; } } return 0; }
BZOJ2809: [Apio2012]dispatching
我們考慮,維護大根堆,費用大於M就彈出堆頂,在給出的樹上完成操作,用dfs實現。
附上代碼:
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <queue> using namespace std; #define N 100005 #define ll long long struct no { int to,next; }e[N]; int head[N],cnt,a[N],b[N],fa[N],n,m; struct node { int ls,rs,x,dis; }mp[N]; void add(int x,int y) { e[cnt].to=y; e[cnt].next=head[x]; head[x]=cnt++; return ; } int find(int x) { if(x==fa[x])return x; return fa[x]=find(fa[x]); } int merge(int x,int y) { if(!x)return y; if(!y)return x; if(mp[x].x<mp[y].x)swap(x,y); mp[x].rs=merge(mp[x].rs,y); if(mp[mp[x].ls].dis<mp[mp[x].rs].dis)swap(mp[x].ls,mp[x].rs); mp[x].dis=mp[mp[x].rs].dis+1; return x; } ll ans,sum[N]; int siz[N]; void dfs(int x,int from) { sum[x]=a[x]; siz[x]=1; for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; if(to1!=from) { dfs(to1,x); sum[x]+=sum[to1]; int fx=find(x),fy=find(to1); fa[fx]=fa[fy]=merge(fx,fy); siz[x]+=siz[to1]; } } while(sum[x]>m) { siz[x]--; int fx=find(x); sum[x]-=mp[fx].x; mp[fx].x=0; fa[fx]=fa[mp[fx].ls]=fa[mp[fx].rs]=merge(mp[fx].ls,mp[fx].rs); } ans=max(1ll*b[x]*siz[x],ans); return ; } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { fa[i]=i; int x; scanf("%d%d%d",&x,&a[i],&b[i]); mp[i].x=a[i]; if(!x)continue; add(x,i); } dfs(1,0); printf("%lld\n",ans); return 0; }
BZOJ3011: [Usaco2012 Dec]Running Away From the Barn
這題方法不少,可並堆可以實現,每次將距離大於L的彈出堆頂,同時需要記錄堆中元素個數,比較水,記得開long long
附上代碼:
#include <cstdio> #include <algorithm> #include <iostream> #include <queue> #include <cmath> #include <cstring> #include <cstdlib> using namespace std; #define N 200005 #define ll long long struct node { int dis,ls,rs; ll x; }mp[N]; struct no { int to,next; ll val; }e[N]; int head[N],cnt; void add(int x,int y,ll z) { e[cnt].to=y; e[cnt].val=z; e[cnt].next=head[x]; head[x]=cnt++; return ; } int fa[N],n,siz[N]; ll dep[N],L; int merge(int x,int y) { if(!x)return y; if(!y)return x; if(mp[x].x<mp[y].x)swap(x,y); mp[x].rs=merge(mp[x].rs,y); if(mp[mp[x].rs].dis>mp[mp[x].ls].dis)swap(mp[x].ls,mp[x].rs); mp[x].dis=mp[mp[x].rs].dis+1; return x; } int find(int x) { if(x==fa[x])return x; return fa[x]=find(fa[x]); } void dfs(int x,int from) { siz[x]=1; for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; if(to1!=from) { mp[to1].x=dep[to1]=dep[x]+e[i].val; dfs(to1,x); siz[x]+=siz[to1]; int fx=find(x),fy=find(to1); fa[fx]=fa[fy]=merge(fx,fy); } } int fx=find(x); while(mp[fx].x>L+dep[x]) { fa[fx]=fa[mp[fx].ls]=fa[mp[fx].rs]=merge(mp[fx].ls,mp[fx].rs); siz[x]--; fx=find(x); } return ; } int main() { fa[1]=1; memset(head,-1,sizeof(head)); scanf("%d%lld",&n,&L); for(int i=2;i<=n;i++) { fa[i]=i; int x; ll y; scanf("%d%lld",&x,&y); add(x,i,y); } dfs(1,0); for(int i=1;i<=n;i++) { printf("%d\n",siz[i]); } return 0; }
BZOJ4003: [JLOI2015]城池攻占
我寫過這題的題解,就不重復了,附上鏈接:https://www.cnblogs.com/Winniechen/p/8890801.html
BZOJ3252: 攻略
網上的題解給的都是線段樹+dfs序,挺裸的,可並堆也可以實現,跑的飛起,代碼精悍。附上鏈接:https://www.cnblogs.com/Winniechen/p/8990559.html
可並堆