https://nanti.jisuanke.com/t/41356
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace FastIO {
#define BUF_SIZE 1000000
bool IOError = 0;
inline char NextChar() {
static char buf[BUF_SIZE], *pl = buf + BUF_SIZE, *pr = buf + BUF_SIZE;
if(pl == pr) {
pl = buf, pr = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pr == pl) {
IOError = 1;
return -1;
}
}
return *pl++;
}
#undef BUF_SIZE
inline bool Blank(char c) {
return c == ' ' || c == '
' || c == '
' || c == ' ';
}
template<class T> inline void Read(T &x) {
char c;
while(Blank(c = NextChar()));
if(!IOError) {
for(x = 0; '0' <= c && c <= '9'; c = NextChar())
x = (x << 3) + (x << 1) + c - '0';
}
}
template<class T> inline void PutChar(T x) {
if(x > 9)
PutChar(x / 10);
putchar(x % 10 + '0');
}
template<class T> inline void Write(T &x) {
PutChar(x);
putchar('
');
}
}
using namespace FastIO;
const int MAXN = 2e5;
//因为题目的数据有0,所以全部+1偏移了一位
const int H = 2e5 + 1;
int bit[H + 5];
inline void clear() {
memset(bit, 0, sizeof(bit));
}
inline void add(int x, int v) {
for(; x <= H; x += x & -x) {
bit[x] += v;
}
}
inline void set0(int x) {
for(; x <= H; x += x & -x) {
bit[x] = 0;
}
}
inline int sum(int x) {
int res = 0;
for(; x ; x -= x & -x) {
res += bit[x];
}
return res;
}
struct Query {
int top, x, d1;
bool operator<(const Query &q)const {
return x < q.x;
}
} q[5 * MAXN + 5], tq[5 * MAXN + 5];
int ans[MAXN + 5];
bool vis[MAXN + 5];
//超过该界时不进行取消树状数组,直接重建,因为树状数组有很多加法、判断之类的,而memset快得多
const int BUILDLIMIT = 2e4;
void solve(const int &l, const int &r, bool fl = false) {
if(l == r)
return;
if(!fl) {
//only update,这个剪枝应该功能强大
bool ou = true;
for(int i = l; i <= r ; i++) {
//发现询问操作,break
if((q[i].top & 3) >= 2) {
ou = false;
break;
}
}
if(ou) {
sort(q + l, q + r + 1);
return;
}
}
int mid = (l + r) >> 1;
solve(l, mid);
solve(mid + 1, r);
int i = l, j = mid + 1, top = 0;
while(i <= mid || j <= r) {
if(i > mid || (j <= r && q[j].x < q[i].x)) {
//把右边的询问加进来
if((q[j].top & 3) >= 2)
tq[++top] = q[j];
++j;
} else {
//把左边的修改加进来
if((q[i].top & 3) <= 1)
tq[++top] = q[i];
++i;
}
}
//真正进行的修改操作的次数,用来辅助判断直接重建,可能是负优化
//int cnt=0;
for(int i = 1, nxt; i <= top; i = nxt) {
for(nxt = i + 1; nxt <= top && tq[i].x == tq[nxt].x; ++nxt);
for(int j = i; j < nxt; ++j) {
//把修改操作执行
if((tq[j].top & 3) == 1) {
add(tq[j].d1, 1);
//++cnt;
} else if((tq[j].top & 3) == 0) {
add(tq[j].d1, -1);
//++cnt;
}
}
for(int j = i; j < nxt; ++j) {
//把询问操作执行
if((tq[j].top & 3) == 2) {
//前面的转换已经把l可能产生的贡献已经清除了
ans[tq[j].top >> 2] -= sum(tq[j].d1);
} else if((tq[j].top & 3) == 3) {
ans[tq[j].top >> 2] += sum(tq[j].d1);
//op2和op3都是成对出现的,只对其中一个赋值就可以了
vis[tq[j].top >> 2] = true;
}
}
}
if(!fl) {
if(cnt < BUILDLIMIT) {
for(int j = 1; j <= top; ++j) {
//对应撤销修改操作
if((tq[j].top & 3) == 1)
add(tq[j].d1, -1);
else if((tq[j].top & 3) == 0)
add(tq[j].d1, +1);
}
} else {
//直接重建
clear();
}
merge(q + l, q + mid + 1, q + mid + 1, q + r + 1, tq + 1);
for(int j = l; j <= r; ++j)
q[j] = tq[j - l + 1];
}
return;
}
int a[MAXN + 5], b[MAXN + 5];
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int n, m;
Read(n), Read(m);
int qtop = 0;
for(int i = 1; i <= n; ++i) {
Read(a[i]);
b[i] = (a[i] == a[i - 1]) ? 0 : a[i];
q[++qtop].top = 1;
q[qtop].x = i;
q[qtop].d1 = b[i] + 1;
}
for(int i = 1, op; i <= m; ++i) {
Read(op);
if(op == 1) {
int x, y;
Read(x), Read(y);
q[++qtop].top = i << 2;
q[qtop].x = x;
q[qtop].d1 = b[x] + 1;
q[++qtop].top = i << 2;
q[qtop].x = x + 1;
q[qtop].d1 = b[x + 1] + 1;
a[x] = y;
b[x] = (a[x] == a[x - 1]) ? 0 : a[x];
b[x + 1] = (a[x + 1] == a[x]) ? 0 : a[x + 1];
q[++qtop].top = i << 2 | 1;
q[qtop].x = x;
q[qtop].d1 = b[x] + 1;
q[++qtop].top = i << 2 | 1;
q[qtop].x = x + 1;
q[qtop].d1 = b[x + 1] + 1;
} else {
int l, r, x, y;
Read(l), Read(r), Read(x), Read(y);
//op2是要被减去的,op3是要被加上的
q[++qtop].top = i << 2 | 2;
//这里询问的就是要l而不是l-1,为了把l可能产生的贡献去掉然后加回来
q[qtop].x = l;
q[qtop].d1 = y + 1;
q[++qtop].top = i << 2 | 3;
//这里询问的就是要l而不是l-1,为了把l可能产生的贡献去掉然后加回来
q[qtop].x = l;
q[qtop].d1 = x - 1 + 1;
q[++qtop].top = i << 2 | 3;
q[qtop].x = r;
q[qtop].d1 = y + 1;
q[++qtop].top = i << 2 | 2;
q[qtop].x = r;
q[qtop].d1 = x - 1 + 1;
//把l的贡献加回来
if(x <= a[l] && a[l] <= y)
++ans[i];
}
}
solve(1, qtop, true);
for(int i = 1; i <= m; ++i) {
if(vis[i])
Write(ans[i]);
}
}
天使玩偶
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace FastIO {
#define BUF_SIZE 1000000
bool IOError = 0;
inline char NextChar() {
static char buf[BUF_SIZE], *pl = buf + BUF_SIZE, *pr = buf + BUF_SIZE;
if(pl == pr) {
pl = buf, pr = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pr == pl) {
IOError = 1;
return -1;
}
}
return *pl++;
}
#undef BUF_SIZE
inline bool Blank(char c) {
return c == ' ' || c == '
' || c == '
' || c == ' ';
}
template<class T> inline void Read(T &x) {
char c;
while(Blank(c = NextChar()));
if(!IOError) {
for(x = 0; '0' <= c && c <= '9'; c = NextChar())
x = (x << 3) + (x << 1) + c - '0';
}
}
template<class T> inline void Read2(T &x) {
char c;
bool f = 0;
while(Blank(c = NextChar()));
if(!IOError) {
if(c == '-') {
f = 1;
c = NextChar();
}
for(x = 0; '0' <= c && c <= '9'; c = NextChar())
x = (x << 3) + (x << 1) + c - '0';
}
if(f)
x = -x;
}
template<class T> inline void PutChar(T x) {
if(x > 9)
PutChar(x / 10);
putchar(x % 10 + '0');
}
template<class T> inline void Write(T &x) {
PutChar(x);
putchar('
');
}
template<class T> inline void Write2(T &x) {
if(x < 0) {
putchar('-');
PutChar(-x);
} else
PutChar(x);
putchar('
');
}
}
using namespace FastIO;
const int INF = 0x3f3f3f3f;
//将题目的[0,1e6]偏移到[1,1e6+1]
const int H = 1e6 + 1;
int bit[H + 5];
inline void build() {
memset(bit, INF, sizeof(bit));
}
void update(int x, int v) {
for(; x <= H; x += x & -x) {
if(v < bit[x])
bit[x] = v;
}
}
void unupdate(int x) {
for(; x <= H; x += x & -x)
bit[x] = INF;
}
int query(int x) {
int res = INF;
for(; x >= 1; x -= x & -x) {
if(bit[x] < res)
res = bit[x];
}
return res;
}
const int MAXNM = 1e6;
struct Query {
int op, x, y;
bool operator<(const Query &q)const {
return x < q.x;
}
} q[MAXNM + 5], tq[MAXNM + 5];
inline int before_calc(int l, int r) {
int mid = (l + r) >> 1;
int i = l, j = mid + 1, top = 0;
while(i <= mid || j <= r) {
if(i > mid || (j <= r && q[j].x < q[i].x)) {
//把右边的询问加进来
if((q[j].op & 1) == 0)
tq[++top] = q[j];
++j;
} else {
//把左边的修改加进来
if((q[i].op & 1) == 1)
tq[++top] = q[i];
++i;
}
}
return top;
}
inline void after_calc(int l, int r, int tqtop) {
int mid = (l + r) >> 1;
merge(q + l, q + mid + 1, q + mid + 1, q + r + 1, tq + 1);
for(int j = l; j <= r; ++j)
q[j] = tq[j - l + 1];
}
int ans[MAXNM + 5];
//超过该界时不进行取消树状数组,直接重建,因为树状数组有很多加法、判断之类的,而memset快得多
const int BUILDLIMIT = 5e4;
int calc_upleft(int tqtop) {
int maxy = -INF;
for(int i = 1; i <= tqtop; ++i) {
if(!(tq[i].op & 1))
maxy = max(maxy, H - tq[i].y + 1);
}
if(maxy != INF) {
int cnt = 0;
for(int i = 1, nxt; i <= tqtop; i = nxt) {
for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
for(int j = i; j < nxt; ++j) {
if(tq[j].op & 1 && H - tq[j].y + 1 <= maxy) {
update(H - tq[j].y + 1, (-tq[j].x + tq[j].y));
++cnt;
}
}
for(int j = i; j < nxt; ++j) {
if(!(tq[j].op & 1))
ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (tq[j].x - tq[j].y) + query(H - tq[j].y + 1));
}
}
if(cnt < BUILDLIMIT) {
for(int i = 1; i <= tqtop; ++i) {
if(tq[i].op & 1 && H - tq[i].y + 1 <= maxy)
unupdate(H - tq[i].y + 1);
}
} else
build();
}
}
int calc_downleft(int tqtop) {
int maxy = -INF;
for(int i = 1; i <= tqtop; ++i) {
if(!(tq[i].op & 1))
maxy = max(maxy, tq[i].y);
}
if(maxy != INF) {
int cnt = 0;
for(int i = 1, nxt; i <= tqtop; i = nxt) {
for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
for(int j = i; j < nxt; ++j) {
if(tq[j].op & 1 && tq[j].y <= maxy) {
update(tq[j].y, (-tq[j].x - tq[j].y));
++cnt;
}
}
for(int j = i; j < nxt; ++j) {
if(!(tq[j].op & 1))
ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (tq[j].x + tq[j].y) + query(tq[j].y));
}
}
if(cnt < BUILDLIMIT) {
for(int i = 1; i <= tqtop; ++i) {
if(tq[i].op & 1 && tq[i].y <= maxy)
unupdate(tq[i].y);
}
} else
build();
}
}
int calc_upright(int tqtop) {
int maxy = -INF;
for(int i = 1; i <= tqtop; ++i) {
if(!(tq[i].op & 1))
maxy = max(maxy, H - tq[i].y + 1);
}
if(maxy != INF) {
int cnt = 0;
for(int i = tqtop, nxt; i >= 1; i = nxt) {
for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
for(int j = i; j > nxt; --j) {
if(tq[j].op & 1 && H - tq[j].y + 1 <= maxy) {
update(H - tq[j].y + 1, (tq[j].x + tq[j].y));
++cnt;
}
}
for(int j = i; j > nxt; --j) {
if(!(tq[j].op & 1))
ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (-tq[j].x - tq[j].y) + query(H - tq[j].y + 1));
}
}
if(cnt < BUILDLIMIT) {
for(int i = 1; i <= tqtop; ++i) {
if(tq[i].op & 1 && H - tq[i].y + 1 <= maxy)
unupdate(H - tq[i].y + 1);
}
} else
build();
}
}
int calc_downright(int tqtop) {
int maxy = -INF;
for(int i = 1; i <= tqtop; ++i) {
if(!(tq[i].op & 1))
maxy = max(maxy, tq[i].y);
}
if(maxy != INF) {
int cnt = 0;
for(int i = tqtop, nxt; i >= 1; i = nxt) {
for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
for(int j = i; j > nxt; --j) {
if(tq[j].op & 1 && tq[j].y <= maxy) {
++cnt;
update(tq[j].y, (tq[j].x - tq[j].y));
}
}
for(int j = i; j > nxt; --j) {
if(!(tq[j].op & 1))
ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (-tq[j].x + tq[j].y) + query(tq[j].y));
}
}
if(cnt < BUILDLIMIT) {
for(int i = 1; i <= tqtop; ++i) {
if(tq[i].op & 1 && tq[i].y <= maxy)
unupdate(tq[i].y);
}
} else
build();
}
}
void solve(int l, int r, bool firstlayer = false) {
if(l == r)
return;
if(!firstlayer) {
bool all1 = true;
for(int i = l; i <= r ; i++) {
if(!(tq[i].op & 1)) {
all1 = false;
break;
}
}
if(all1) {
sort(q + l, q + r + 1);
return;
}
}
int mid = (l + r) >> 1;
solve(l, mid);
solve(mid + 1, r);
//这里是没必要每一层都排序的,事实上是每一层直接归并就可以了
int tqtop = before_calc(l, r);
calc_upleft(tqtop);
calc_downleft(tqtop);
calc_upright(tqtop);
calc_downright(tqtop);
if(!firstlayer)
after_calc(l, r, tqtop);
return;
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int n, m;
Read(n), Read(m);
//scanf("%d%d", &n, &m);
int qtop = 0;
for(int i = 1; i <= n; ++i) {
int x, y;
Read(x), Read(y);
++qtop;
q[qtop].op = qtop << 1 | 1;
q[qtop].x = x + 1;
q[qtop].y = y + 1;
}
for(int i = 1; i <= m; ++i) {
int op, x, y;
Read(op), Read(x), Read(y);
++qtop;
q[qtop].op = (qtop << 1) | (op & 1);
q[qtop].x = x + 1;
q[qtop].y = y + 1;
}
build();
memset(ans, INF, sizeof(ans[0]) * (n + m + 1));
solve(1, qtop, true);
const int MAXANS = 5e6;
for(int i = 1; i <= qtop; ++i) {
if(ans[i] <= MAXANS) {
Write(ans[i]);
}
}
}