2020 Multi-University Training Contest 9 G题
题意:有N个有各自高度的位置,按1~N从左到右排列。现在我们有两种操作:
- x y将第x列,第y行的方块,包括它上面的方块从右往左的移动过去,同时推动前面的方块前进,当然,最前面的那个方块,会根据重力掉下去。非法状态(或者不能移动状态)不移动。
- x,查询第x列的方块高度是多少。
于是,很明显的,我们可以考虑大于等于y的最长向前的连续,我们找到第一个小于y的高度的列的位置,那么,从
到x的这个连续段内肯定是都要往前推的,不考虑特殊情况,那么可以看成
到x向前移动一格,然后原本
的这个点的高度就被删去了,再后来,第x位的值会被改成
,并且原本
的高度会加上
溢出的块的个数。
于是,我们可以用一个平衡树数据结构来维护一下这个。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7;
int N, Q, b[maxN];
namespace Splay_Tree
{
#define Min_3(a, b, c) min(a, min(b, c))
int root;
struct node
{
int ff, h, siz, ch[2], mn_h;
ll sum_h;
inline void Init(int height, int fa)
{
ff = fa; h = sum_h = height;
ch[0] = ch[1] = 0;
siz = 1;
}
} t[maxN];
inline void pushup(int u)
{
t[u].siz = t[t[u].ch[0]].siz + t[t[u].ch[1]].siz + 1;
t[u].sum_h = t[t[u].ch[0]].sum_h + t[t[u].ch[1]].sum_h + t[u].h;
t[u].mn_h = Min_3(t[t[u].ch[0]].mn_h, t[t[u].ch[1]].mn_h, t[u].h);
}
int build(int fa, int l, int r)
{
if(l > r) return 0;
int mid = HalF;
t[mid].Init(b[mid], fa);
t[mid].ch[0] = build(mid, l, mid - 1);
t[mid].ch[1] = build(mid, mid + 1, r);
pushup(mid);
return mid;
}
inline void Rotate(int x)
{
int y = t[x].ff, z = t[y].ff, k = t[y].ch[1] == x;
t[z].ch[t[z].ch[1] == y] = x;
t[x].ff = z;
t[y].ch[k] = t[x].ch[k ^ 1];
t[t[x].ch[k ^ 1]].ff = y;
t[x].ch[k ^ 1] = y;
t[y].ff = x;
pushup(y);
pushup(x);
}
inline void Splay(int x, int goal)
{
while(t[x].ff ^ goal)
{
int y = t[x].ff, z = t[y].ff;
if(z ^ goal) (t[z].ch[0] == y) ^ (t[y].ch[0] == x) ? Rotate(x) : Rotate(y);
Rotate(x);
}
if(!goal) root = x;
}
inline int Kth(int x)
{
int u = root, y;
while(true)
{
y = t[u].ch[0];
if(x > t[y].siz + 1)
{
x -= t[y].siz + 1;
u = t[u].ch[1];
}
else
{
if(t[y].siz >= x) u = y;
else return u;
}
}
}
inline int find_pre(int u, int y)
{
u = t[u].ch[0];
while (true)
{
if(t[t[u].ch[1]].mn_h < y) u = t[u].ch[1];
else if(t[u].h < y) return u;
else u = t[u].ch[0];
}
}
};
using namespace Splay_Tree;
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &N, &Q);
for(int i=1; i<=N; i++)
{
scanf("%d", &b[i]);
}
t[0].mn_h = INF; t[0].siz = 0; t[0].h = 0; t[0].sum_h = 0;
Splay_Tree::root = build(0, 1, N);
ll ans, tmp;
for(int i=1, op, x, y, pos, beg_pos, u, det, fir; i<=Q; i++)
{
scanf("%d%d", &op, &x);
if(op == 1)
{
scanf("%d", &y);
pos = Kth(x);
Splay(pos, 0);
if(y > t[pos].h || t[t[pos].ch[0]].mn_h >= y)
{
printf("0\n");
continue;
}
beg_pos = find_pre(pos, y);
Splay(beg_pos, pos);
tmp = t[t[beg_pos].ch[1]].siz;
ans = t[t[beg_pos].ch[1]].sum_h - tmp * (y - 1) + t[pos].h - y + 1;
printf("%lld\n", ans);
if(t[beg_pos].ch[1])
{
u = t[beg_pos].ch[1];
while(t[u].ch[0]) u = t[u].ch[0];
fir = u;
det = t[u].h - y + 1;
t[beg_pos].h += det;
/*Solve*/
Splay(fir, beg_pos);
t[fir].h = y - 1;
t[beg_pos].ch[1] = t[fir].ch[1];
t[t[fir].ch[1]].ff = beg_pos;
t[fir].ch[1] = t[pos].ch[1];
t[t[pos].ch[1]].ff = fir;
t[pos].ch[1] = fir;
t[fir].ff = pos;
pushup(fir);
pushup(beg_pos);
pushup(pos);
/*end*/
}
else
{
det = t[pos].h - y + 1;
t[beg_pos].h += det;
t[pos].h = y - 1;
pushup(beg_pos);
pushup(pos);
}
}
else
{
pos = Kth(x);
printf("%d\n", t[pos].h);
}
}
for(int i=1, pos; i<=N; i++)
{
pos = Kth(i);
printf("%d%c", t[pos].h, i == N ? '\n' : ' ');
}
}
return 0;
}