2024.10.10

今日总结:
写完了南外的专题中的D:subsequence
首先这道题可以用简单的dp来做时间复杂度是O(n^2)这显然是一分没有的。
然后考虑优化可以用平衡树维护dp值的差分,每次在平衡树上二分找到使第二种策略最优解的位置
然后插入一个位置,对后缀进行区间加时间复杂度是O(nlogn)就能过。
但是仔细思考了一下正解:
正解是考虑分块,对于每一个内的凸壳,每次在凸壳上二分寻找最大值,选择元素将他删除,
然后重构凸壳这种时间复杂度是O(nsqrt(n)logn)的在时间上已经有了很大进步,
继续考虑优化,还可以在这个的基础上用用一个指针来代替二分然后就得到了一个O(n
sqrt(n))的最优做法

点击查看代码
#include<bits/stdc++.h>
 
using namespace std;

#define int long long
const int N = 1e5 + 10;

#define l_son dp[v][0]
#define r_son dp[v][1]
 
int n,rt;
int a[N],siz[N],p[N],add[N];
int dp[N][2],fa[N];

inline void push_up(int v) 
{
	siz[v] = siz[l_son] + siz[r_son];
    siz[v] ++;
}

inline void Add(int v,int f) 
{
    p[v] += f;
    add[v] += f;
}
 
inline void push_down(int v) 
{
    if(add[v]) 
    {
        if(l_son) Add(l_son,add[v]);
        if(r_son) Add(r_son,add[v]);
        add[v] = 0;
    }
}
 
inline void root(int v) 
{
    int f = fa[v],gr = fa[f];
    int sn = v == dp[f][1],son = dp[v][!sn];
    if(gr) dp[gr][f == dp[gr][1]] = v;
    dp[f][sn] = son;
    dp[v][!sn] = f;
    fa[v] = gr,fa[f] = v;
    if(son) fa[son] = f;
    push_up(f),push_up(v);
}
 
inline void splay(int v) 
{
    static int st[N],top;
    st[top = 1] = v;
    for(int i = v;fa[i];i = fa[i]) 
        st[++ top] = fa[i];
    for(int i = top;i >= 1;i --) 
        push_down(st[i]);
    while(fa[v]) 
    {
        int f = fa[v],gr = fa[f];
        if(gr) root(f == dp[gr][1] ^ v == dp[f][1] ? v : f);
        root(v);
    }
    rt = v;
}
 
int tot;

inline int Find(int k) 
{
    int v = rt;
    while(1) 
    {
        if(siz[l_son] + 1 == k) return v;
        if(siz[l_son] >= k) v = l_son;
        else k -= siz[l_son] + 1,v = r_son;
    }
}
 
inline int Find_rk(int v) 
{
    splay(v);
    return siz[l_son] + 1;
}
 
inline void Insert(int &v,int k,int id) 
{
    if(!v) 
    {
        v = id;
        push_up(v);
        return;
    }
    if(siz[l_son] >= k - 1) 
    {
        Insert(l_son,k,id);
        fa[l_son] = v;
    } 
    else 
    {
        Insert(r_son,k - siz[l_son] - 1,id);
        fa[r_son] = v;
    }
    push_up(v);
}
 
int pos;

inline void B_Find(int v,int a,int pre,int &pos) 
{
    if(!v) return;
    push_down(v);
    int now = pre + siz[l_son] + 1;
    if(a * now >= p[v]) 
    {
        pos = v;
        B_Find(l_son,a,pre,pos);
    }
    else B_Find(r_son,a,pre + siz[l_son] + 1,pos);
}
 
inline void Print(int v,int &ans) 
{
    if(!v) return;
    push_down(v);
    Print(l_son,ans);
    ans += p[v];
    printf("%lld ",ans);
    Print(r_son,ans);
}
 
signed main() 
{
    scanf("%lld",&n);
    for(int i = 1;i <= n;i ++) 
        scanf("%lld",&a[i]);
    rt = 1;
    push_up(rt);
    p[rt] = a[1];
    for(int i = 2;i <= n;i ++) 
    {
        B_Find(rt,a[i],0,pos = i);
        if(pos != i) splay(pos);
        int rk = pos == i ? i : Find_rk(pos);
        p[i] = a[i] * rk;
        Insert(rt,rk,i);
        splay(i);
        if(dp[i][1]) Add(dp[i][1],a[i]);
    }
    int ans = 0;
    Print(rt,ans);
    return 0;
}

复习了拓扑排序。和有负环的图论,和tarjian算法

posted @ 2024-10-10 22:16  Kevinhwbb  阅读(6)  评论(0编辑  收藏  举报