刷题记录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;
}
任何时候都有比放弃更好的选择。