poj3415解题报告
Ubuntu 14.04LTS 更新手记

左偏树

ProKil posted @ 2014年4月26日 12:00 in Informatics with tags 解题报告 OI zoj2334 apio2012 dispatching , 975 阅读

左偏树是一种可合并堆。可合并堆具体有fibonacci堆,二项堆和左偏树等,左偏树是其中较好实现的一种。

它满足一下几个性质,我总结为堆性、左偏性和递归性。顾名思义,堆性就是满足大(小)根堆的性质——子树的根的关键字大(小)于其两个孩子。左偏性,指每个节点左孩子的dist不小于右孩子(下一段再介绍dist值),即 [tex]dist(left child) \ge dist(right child)[/tex]。递归性指一个节点的左右孩子都是左偏树。

dist值的定义为 [tex]dist(n) =\begin{cases} -1,&\mbox{if }n\mbox{ is null} \\dist(right child)+1,&\mbox{otherwise}\end{cases}[/tex]

zoj2334是左偏树最简单应用,加个读入优化就rank1了

Zoj2334_Status

代码很短,见下:

 

#include<cstdio>
#include<cstring>
#include<climits>
#define maxn 1000005
int n,m,tot,root[maxn],v[maxn],l[maxn],r[maxn],d[maxn],father[maxn];
void swap(int &a,int &b){
    int c = a;a = b;b = c;
}
int merge(int x,int y){
    if(!x) return y;
    if(!y) return x;
    if(v[x] < v[y]) swap(x,y);
    r[x] = merge(r[x],y);
    if(d[l[x]] < d[r[x]]) swap(l[x],r[x]);
    d[x] = d[r[x]] + 1;
    return x;
}
int init(int x){l[tot] = r[tot] = d[tot] = 0;v[tot++] = x;return tot-1;}
int insert(int x,int y){return merge(x,init(y));}
int top(int x){return v[x];}
int pop(int x){return merge(l[x],r[x]);}
int getfather(int x){
    if(x == father[x]) return x;
    father[x] = getfather(father[x]);
    return father[x];
}
int getint(){
    char c = getchar();
    int ret = 0;
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9'){
        ret = ret * 10 + c - '0';
        c = getchar();
        }
    return ret;
}     
int main(){
    while(scanf("%d",&n) == 1){
        tot = 0;
        for(int i = 1;i<=n;i++) father[i] = i;
        for(int i = 1;i<=n;i++){
            int a = getint();
            root[i] = init(a);
            }
        scanf("%d",&m);
        for(int i = 0;i<m;i++){
            int x = getint(),y = getint();
            if((x = getfather(x)) == (y = getfather(y))) {printf("-1\n");continue;}
            int a = top(root[x]),b = top(root[y]);
            root[x] = pop(root[x]);
            root[x] = insert(root[x],a >> 1);
            root[y] = pop(root[y]);
            root[y] = insert(root[y],b >> 1);
            father[x] = y;
            root[y] = merge(root[y],root[x]);
            printf("%d\n",top(root[y]));
         }
         }
    return 0;
}          

apio2012的dispatching就可以用左偏树实现。对每个人根据薪水建立一个大根左偏树。按照拓扑序,访问节点时,不断去除最大值,直到剩余薪水和小于m,更新最大值,并将自己的左偏树合并入其上级的左偏树中即可。

代码同样很短,见下:

 

#include<cstdio>
#include<cstring>
#include<climits>
#include<queue>
using namespace std;
#define maxn 100005
int n,root[maxn],v[maxn],d[maxn],l[maxn],r[maxn],L[maxn],C[maxn],B[maxn],tot,de[maxn];
long long m,Max,ans[maxn],sum[maxn];
queue<int> Q;
void swap(int &a,int &b){
    int c = a;a = b;b = c;
}
int merge(int x,int y){
	if(!x) return y;
    if(!y) return x;
    if(v[x] < v[y]) swap(x,y);
    r[x] = merge(r[x],y);
    if(d[l[x]] < d[r[x]]) swap(l[x],r[x]);
    d[x] = d[r[x]] + 1;
    return x;
}
int init(int x){v[tot++] = x;return tot-1;}
int top(int x){return v[x];}
int pop(int x){return merge(l[x],r[x]);}
int insert(int x,int y){return merge(x,init(y));}
int getint(){
    char c = getchar();
    int ret = 0;
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9'){
        ret = ret * 10 + c - '0';
        c = getchar();
        }
    return ret;
} 
int main(){
    scanf("%d%lld",&n,&m);
    tot = 1;
    for(int i = 1;i<=n;i++){
        B[i] = getint(),C[i] = getint(),L[i] = getint();
        if(B[i]) de[B[i]]++;
        root[i] = init(C[i]);
        ans[i] = 1;
        sum[i] = C[i];
        }
    for(int i = 1;i<=n;i++) if(!de[i]) Q.push(i);
    while(!Q.empty()){
        int q = Q.front();
        Q.pop();
        while(sum[q] > m){
            sum[q] -= top(root[q]);
            root[q] = pop(root[q]);
            ans[q]--;
            }
        if(Max < (long long)ans[q] * (long long) L[q]) Max = (long long) ans[q] * (long long) L[q];
        root[B[q]] = merge(root[B[q]],root[q]);
        ans[B[q]] += ans[q];
        sum[B[q]] += sum[q];
        de[B[q]]--;
        if(!de[B[q]]) Q.push(B[q]);
        }
    printf("%lld\n",Max);
    return 0;
}        
Avatar_small
TNDGE Model Paper Cl 说:
2022年8月20日 15:43

Tamilnadu Board Model Paper 2023 Class 6 Pdf Download with Answers for Tamil Medium, English Medium, Hindi Medium, Urdu Medium & Students for Small Answers, Long Answer, Very Long Answer Questions, and Essay Type Questions to Term1 & Term2 Exams at official website. TNDGE Model Paper Class 6 New Exam Scheme or Question Pattern for Sammittive Assignment Exams (SA1 & SA2): Very Long Answer (VLA), Long Answer (LA), Small Answer (SA), Very Small Answer (VSA), Single Answer, Multiple Choice and etc.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter