[Ynoi2018]五彩斑斓的世界
Posted sai0511
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Ynoi2018]五彩斑斓的世界相关的知识,希望对你有一定的参考价值。
分块毒瘤题。如果真的想好好练习思维以及代码的话就请不要使用( ext{WC})讲过的黑科技指令集。
正文部分:
由乃题必定分块。
我们可以将同一个块内值相同的用并查集维护起来,因为如果是一个块内相同的值打标机怎么改都一样。
接着谈修改,我们设块内最大值为( ext{mx}),修改的值为( ext{v})
如果(v*2>mx)的话就改大于( ext{v})的,否则就改小于( ext{v})的
原理是因为如果大于( ext{v})的比较少的话改大的,否则改小的。
改小的时候我们可以把小的数全部加上( ext{v}),然后对这个块打上一个减标记。
My Code:
// luogu-judger-enable-o2
#pragma GCC optimize("Ofast,fast-math")
#pragma GCC target("avx,avx2")
#include <bits/stdc++.h>
#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define _max(x,y) (x > y ? x : y)
using namespace std;
static char buf[100000],*p1,*p2;
static char pbuf[1000000],*pp(pbuf),st[15];
inline int read() {
register int res(0);register char c(gc);
while(c < ‘0‘ || c > ‘9‘) c = gc;
while(c >= ‘0‘ && c <= ‘9‘) res = res * 10 + c - 48,c = gc;
return res;
}
inline void print(register int v) {
if(!v) *pp++ = 48;
else {
register int tp(0);
while(v) st[++tp] = v % 10 + 48,v /= 10;
while(tp) *pp++ = st[tp--];
}
*pp++ = ‘
‘;
}
int fa[100010],a[100010],bel[100010];
int bl[320],br[320],Max[320],tag[320];
int root[320][100010];
unsigned short cnt[100010];
int n,m,i,j,k,bls;
int getf(int o) {
if(o == fa[o]) return o;
else return fa[o] = getf(fa[o]);
}
inline void build(int num) {
Max[num] = 0;
for(register int i = bl[num];i <= br[num];++i) {
if(!root[num][a[i]]) {
root[num][a[i]] = i;
fa[i] = i;
cnt[root[num][a[i]]] = 1;
} else {
fa[i] = root[num][a[i]];
cnt[root[num][a[i]]]++;
}
Max[num] = _max(Max[num],a[i]);
}
return;
}
inline void pd(int num) {
for(register int i = bl[num];i <= br[num];++i) {
a[i] = a[getf(i)];
cnt[root[num][a[i]]] = 0;root[num][a[i]] = 0;
}
for(register int i = bl[num];i <= br[num];++i) {
a[i] -= tag[num];fa[i] = 0;
}
tag[num] = 0;
return;
}
inline void change1(int l,int r,int x) {
for(register int i = bel[l];i <= bel[r];++i) pd(i);
for(register int i = l;i <= r;++i) {
if(a[i] > x) a[i] -= x;
}
for(register int i = bel[l];i <= bel[r];++i) build(i);
return;
}
inline void rpl(int x,int y,int z) {
if(!root[x][y]) return;
if(!root[x][z]) {
root[x][z] = root[x][y];
cnt[root[x][z]] = cnt[root[x][y]];
a[root[x][y]] = z;
} else {
fa[root[x][y]] = root[x][z];
cnt[root[x][z]] += cnt[root[x][y]];
}
root[x][y] = 0;
cnt[root[x][y]] = 0;
return;
}
inline void change2(int num,int val) {
if(val >= Max[num] - tag[num]) return;
if(val << 1 > Max[num] - tag[num]) {
for(register int i = tag[num] + val + 1;i <= Max[num];++i) rpl(num,i,i - val);
// Max[num] -= val;Chkmax(Max[num],val + tag[num]);
Max[num] = _max(Max[num] - val,val + tag[num]);
} else {
for(register int i = tag[num] + 1;i <= tag[num] + val;++i) rpl(num,i,i + val);
tag[num] += val;
}
return;
}
inline void modify(int l,int r,int x) {
if(bel[l] + 1 >= bel[r]) {
change1(l,r,x);
return;
}
change1(l,br[bel[l]],x);change1(bl[bel[r]],r,x);
for(int i = bel[l] + 1;i < bel[r];++i) change2(i,x);
return;
}
inline int ask1(int l,int r,int x) {
int res = 0;
for(int i = l;i <= r;++i) {
if(a[getf(i)] - tag[bel[i]] == x) res++;
}
return res;
}
inline int ask2(int num,int val) {
if(val + tag[num] >= 100000) return 0;
return cnt[root[num][val + tag[num]]];
}
inline int query(int l,int r,int x) {
if(bel[l] + 1 >= bel[r]) return ask1(l,r,x);
int res = ask1(l,br[bel[l]],x) + ask1(bl[bel[r]],r,x);
for(int i = bel[l] + 1;i < bel[r];i++) res += ask2(i,x);
return res;
}
int main() {
n = read();m = read();bls = sqrt(n) + 1;
for(register int i = 1;i <= n;++i) {
a[i] = read();
bel[i] = (i - 1) / bls + 1;
if(!bl[bel[i]]) bl[bel[i]] = i;
br[bel[i]] = i;
}
for(register int i = 1;i <= bel[n];++i) build(i);
while(m--) {
int opt,l,r,x;opt = read();l = read();r = read();x = read();
if(opt == 1) modify(l,r,x);
else {
print(query(l,r,x));
}
}
fwrite(pbuf,1,pp-pbuf,stdout);
return 0;
}
以上是关于[Ynoi2018]五彩斑斓的世界的主要内容,如果未能解决你的问题,请参考以下文章
❤️ 五彩斑斓的「 算法 」世界需要多「 思考 」 ❤️(建议收藏)