P3521 [POI2011]ROT-Tree Rotations

思路

发现每个子树内的交换情况不会对子树外造成影响,所以可以利用贪心的思想,线段树合并找出当前子树的合并的最小值直接累加给答案即可

我脑补的线段树合并貌似不太优秀的样子。。。每次都要新建节点,学习了直接把y合并到x上的想法,但是因为#define int long long的坏习惯导致MLE,最后还是要写内存池。。。

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define int long long
using namespace std;
struct Node{
    int lson,rson,sz;
}Seg[3000000];
int Nodecnt,ans,min1,min2,n;
queue<int> q;
int getnew(void){
    if(q.size()){
        int t=q.front();
        q.pop();
        Seg[t].lson=Seg[t].rson=Seg[t].sz=0;
        return t;
    }
    return ++Nodecnt;
}
void throwin(int x){
    q.push(x);
}
void build(int l,int r,int &o,int val){
    // printf("%d %d %d %d
",l,r,o,val);
    if(!o)
        o=getnew();
    // printf("%d %d %d %d
",l,r,o,val);
    Seg[o].sz++;
    if(l==r){
        return;
    }
    int mid=(l+r)>>1;
    if(val<=mid)
        build(l,mid,Seg[o].lson,val);
    else
        build(mid+1,r,Seg[o].rson,val);
}
void merge(int &x,int y,int l,int r){
    if(x*y==0){
        x=x+y;
        return;
    }
    min1+=Seg[Seg[x].rson].sz*Seg[Seg[y].lson].sz;
    min2+=Seg[Seg[x].lson].sz*Seg[Seg[y].rson].sz;
    if(l==r){
        Seg[x].sz=Seg[x].sz+Seg[y].sz;
        return;
    }
    Seg[x].sz=Seg[x].sz+Seg[y].sz;
    int mid=(l+r)>>1;
    merge(Seg[x].lson,Seg[y].lson,1,mid);
    merge(Seg[x].rson,Seg[y].rson,mid+1,r);
    throwin(y);
    return;
}
int solve(void){
    int x;
    scanf("%lld",&x);
    if(!x){
        int lson,rson;
        lson=solve();
        rson=solve();
        min1=0;
        min2=0;
        int t=lson;
        merge(t,rson,1,n);
        // printf("%d %d
",min1,min2);
        ans+=min(min1,min2);
        return t;
    }
    else{
        int t=0;
        // printf("ok
");
        build(1,n,t,x);
        // printf("ok
");
        return t;
    }
    return 0;
}
signed main(){
    scanf("%lld",&n);
    solve();
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/dreagonm/p/10556403.html