刷题记录2

小白逛公园

  • 注意线段树的分块思维,以及分治的思维,写了好久,还看了题解

AC code

#include <bits/stdc++.h>
using namespace std;
#define int long long
// P4513 小白逛公园
int read()
{
    int x = 0, f = 1;char ch = getchar();
    while (!isdigit(ch)){if (ch == '-')f = -1;ch = getchar();}
    while (isdigit(ch)){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 5e5 + 9;
inline int min(int a, int b, int c)
{
    return min(min(a, b), c);
}
inline int max(int a, int b, int c){return max(max(a,b),c);}
inline int max(int a, int b, int c,int d){return max(max(a,b),max(c,c));}
class seg
{
public:
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
    struct node
    {
        int l, r, sum, lv, rv; // lv 包含左边界的最大值, rv 包含右边界的最大值
        int ma;
    };
    int a[maxn];
    node t[maxn<<2];
    void update(int p)
    {
        if(t[p].l==t[p].r)return ;// 防止越界
        t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
        t[p].lv = max(t[ls(p)].lv, t[rs(p)].lv + t[ls(p)].sum);
        t[p].rv = max(t[rs(p)].rv, t[ls(p)].rv + t[rs(p)].sum);
        t[p].ma = max(t[ls(p)].ma,t[rs(p)].ma,t[ls(p)].rv+t[rs(p)].lv);
    }
    void build(int p, int l, int r)
    {
        t[p].l = l, t[p].r = r;
        if (l == r)
        {
            t[p].ma=a[l];
            t[p].sum = a[l];
            t[p].lv = a[l];
            t[p].rv = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(ls(p), l, mid);
        build(rs(p), mid + 1, r);
        update(p);
    }
    void change(int p,int x,int v)
    {
        if(t[p].l==t[p].r&&t[p].l==x)
        {
            
            t[p].ma=t[p].rv=t[p].lv=t[p].sum=v;
            return ;
        }
        int mid=(t[p].l+t[p].r)>>1;
        if(mid>=x)change(ls(p),x,v);
        else  change(rs(p),x,v);
        update(p);
    }
    vector<int> ask(int p,int x,int y)
    {
        if(x<=t[p].l&&t[p].r<=y)
        {
            return {t[p].ma,t[p].sum,t[p].lv,t[p].rv};// 0 代表最终的答案 
            
        }
        int mid=(t[p].l+t[p].r)>>1;
        if(mid>=x&&mid<y){
            vector<int> l=ask(ls(p),x,y),r=ask(rs(p),x,y), ans(4,0);
            ans[0]=max(l[0],r[0],r[2]+l[3]);
            ans[1]=l[1]+r[1];
            ans[2]=max(l[2],l[1]+r[2]);
            ans[3]=max(r[3],l[3]+r[1]);
            return ans;
        }
        else if(mid>=x)return ask(ls(p),x,y);
        else if(mid <y) return ask(rs(p),x,y);
    }
};
seg T;

signed main()
{
    int n,m,k,a,b;
    n=read(),m=read();
    for(int i=1;i<=n;i++)T.a[i]=read();
    T.build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        k=read(),a=read(),b=read();
        if(k==1)
        {
            if(a>b)swap(a,b);   
            cout<<T.ask(1,a,b)[0]<<'\n';
        }
        else
        {
            T.change(1,a,b);
        }
    }
    return 0;
}

冒泡排序

  • 主要是思维的转化 $ k $ 轮冒泡排序后剩下的逆序对的数量是 $ \sum\limits_{i=k}^n(i-k) \times a[i] $ , \(a[i]\) 代表前方存在 $ i $ 个比自己大的数的个数 , 通过树状数组就可以转化成 维护两个序列 , $ a[i] $ 和 $ i\times a[i] $ 当然也可以用线段树做,但是树状数组的常数时间更小
#include <bits/stdc++.h>
#define print(x)    cout<<#x <<'='<<x<<'\n'
#define int long long
using namespace std;
int n, m;
int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (!isdigit(c))
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (isdigit(c))
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
const int maxn = 2e5 + 9;
int a[maxn];
int b[maxn], c[maxn], d[maxn], e[maxn];
inline int lowbit(int x) { return x & -x; }
void add(int *ar, int x, int y)
{
    while (x <= n)
    {
        ar[x] += y;
        x += lowbit(x);
    }
}
int sum(int *ar, int x)
{
    int ans = 0;
    while (x>0)
    {
        ans += ar[x];
        x -= lowbit(x);
    }
    return ans;
}
signed main()
{
    n = read(), m = read();
    for (int i = 1; i <= n; i++)
    {
        a[i] = read();
        add(b, a[i], 1);
        int k = i - sum(b, a[i]);
        e[i] = k;
        if (k != 0)
        {
            add(c, k, 1);
            add(d, k, k);
        }
    }
    int x, y;
    for (int i = 1; i <= m; i++)
    {
        x = read(), y = read();
        if (x == 1)
        {
            if (a[y] > a[y + 1])
            {
                int a1 = e[y], a2 = e[y + 1];
                swap(e[y],e[y+1]);
                e[y]--;
                if (a2 != 0)
                    add(c, a2, -1);
                if (a2 - 1 > 0)
                    add(c, a2 - 1, 1);
                if (a2 != 0)
                    add(d, a2, -a2);
                if (a2 - 1 > 0)
                    add(d, a2 - 1, a2 - 1);
                
            }
            else
            {
                int a1 = e[y], a2 = e[y + 1];
                swap(e[y],e[y+1]);
                e[y+1]++;
                add(c, a1 + 1, 1);
            if(a1!=0)    add(c, a1, -1);
                add(d, a1 + 1, a1 + 1);
            if(a1!=0)    add(d, a1, -a1);
            }
            swap(a[y], a[y + 1]);
        }
        else
        {
            // if(y-1!=0)print(sum(d,y-1)),print(sum(c,y-1));
            // print(sum(d,n));
            if(y>=n)cout<<0<<'\n';
            else
            cout << sum(d, n) - (y-1==0?0:sum(d, y-1)) - y * (sum(c, n) - (y-1==0?0:sum(c, y-1))) << '\n';
        }
    }
    return 0;
}
posted @ 2024-08-08 10:55  -风间琉璃-  阅读(1)  评论(0编辑  收藏  举报