洛谷

Codeforces


又是一道卡常题……


思路

YNOI当然要分块啦。

分块之后怎么办?

零散块暴力,整块怎么办?

显然不能暴力改/查询所有的。考虑把相同值的用并查集连在一起,这样修改时就只需要枚举值了。

然而每次修改的\(x\)特别小时仍然复杂度爆炸,发现大于\(x\)的减去\(x\)等价于小于等于\(x\)的加上\(x\),然后整体减去\(x\)。

那么,设一个块的最大值为\(mx\),则

  • \(2x\geq mx\)时枚举\(x<v\leq mx\),把\(v\)的并查集连到\(v-x\)上,复杂度\(O(mx-x)\),\(mx\)变为\(x\)。(即\(mx-=mx-x\))
  • 否则,枚举\(v\leq x\),把\(v\)的并查集连到\(v+x\)上,然后整体减去\(x\),复杂度\(O(x)\),\(mx-=x\)。

你是否发现一件事:在每一块上花\(O(x)\)的时间,就可以使\(mx\)减小\(x\)。也就是说,每一块花费的最多时间是\(O(mx)\),总共就是\(O(\sqrt m \times mx)\)。

也就是说,这种仿佛暴力的算法,复杂度是正确的。

然而,毒瘤出题人既卡空间,又卡时间,所以要AC还是有些麻烦的。

不过CF上给了\(512MB,3000ms\),可以去那里。

CF的题似乎被暴力+pragma艹过去了。出题人活该


代码

没怎么卡常的代码,CF上能过:

#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define sz 100010
#define S 320
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<typename T>inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
template<typename T>inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std; int n,m;
int a[sz]; int fa[sz],size[sz];
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
int blo,pos[sz];
struct hh
{
int L,R;
int tag,mx;
int f[sz];
int val(int x){return a[getfa(x)]-tag;} // the real value of position x
void rebuild()
{
rep(i,L,R) fa[i]=size[i]=0;
tag=mx=0;
rep(i,L,R)
if (!f[a[i]]) f[a[i]]=fa[i]=i,size[i]=1;
else fa[i]=f[a[i]],++size[fa[i]];
rep(i,L,R) mx=max(mx,a[i]);
}
void modify(int x)
{
if (x>=mx) return;
if (2*x>=mx)
{
rep(i,x+1+tag,mx+tag) if (f[i])
{
int y=i-x;
if (f[y]) fa[f[i]]=f[y],size[f[y]]+=size[f[i]];
else f[y]=f[i],a[f[y]]-=x;
f[i]=0;
}
mx=x;
}
else
{
drep(i,x+tag,1+tag) if (f[i])
{
int y=i+x;
if (f[y]) fa[f[i]]=f[y],size[f[y]]+=size[f[i]];
else f[y]=f[i],a[f[y]]+=x;
f[i]=0;
}
tag+=x;mx-=x;
}
}
int query(int x){return x+tag<sz&&f[x+tag]?size[f[x+tag]]:0;}
}b[S]; void init()
{
blo=sqrt(n);
rep(i,1,n)
{
pos[i]=(i-1)/blo+1;
b[pos[i]].R=i;
if (pos[i]!=pos[i-1]) b[pos[i]].L=i;
}
rep(i,1,pos[n]) b[i].rebuild();
}
int tmp[sz];
void change_(int l,int r,int x)
{
int p=pos[l];
rep(i,b[p].L,b[p].R) b[p].f[a[getfa(i)]]=0;
rep(i,b[p].L,b[p].R) tmp[i]=b[p].val(i);
rep(i,b[p].L,b[p].R) a[i]=tmp[i];
rep(i,l,r) if (a[i]>x) a[i]-=x;
b[p].rebuild();
}
void change(int l,int r,int x)
{
int pl=pos[l],pr=pos[r];
if (pl==pr) return change_(l,r,x);
change_(l,b[pl].R,x),change_(b[pr].L,r,x);
if (pl==pr+1) return;
++pl,--pr;
rep(i,pl,pr) b[i].modify(x);
}
int query_(int l,int r,int x)
{
int ret=0,p=pos[l];
rep(i,l,r)
ret+=(b[p].val(i)==x);
return ret;
}
int query(int l,int r,int x)
{
int pl=pos[l],pr=pos[r];
if (pl==pr) return query_(l,r,x);
int ret=query_(l,b[pl].R,x)+query_(b[pr].L,r,x);
if (pl+1==pr) return ret;
++pl,--pr;
rep(i,pl,pr) ret+=b[i].query(x);
return ret;
} int main()
{
file();
read(n,m);
rep(i,1,n) read(a[i]);
init();
while (m--)
{
int z,x,l,r;read(z,l,r,x);
if (z==1) change(l,r,x);
else printf("%d\n",query(l,r,x));
}
return 0;
}

卡常之后的代码,洛谷上可以过:

注意:不保证此代码任何时刻都可通过。我是半夜提交的。

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define rep(i,x,y) for (register int i=x;i<=y;++i)
#define drep(i,x,y) for (register int i=x;i>=y;--i)
#define sz 100010
#define S 320
typedef long long ll;
typedef double db;
char buf[1<<20],*p1=buf,*p2=buf;
inline char getchar(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++;}
inline void read(int& t)
{
t=0;char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
}
char sr[800000],z[10];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(register int x)
{
if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
// void file()
// {
// #ifndef ONLINE_JUDGE
// freopen("a.txt","r",stdin);
// #endif
// }
}
using namespace my_std; int n,m;
int a[sz]; int fa[sz],size[sz];
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
int blo,pos[sz];
struct hh
{
int L,R;
int tag,mx;
int f[sz];
void rebuild()
{
rep(i,L,R) fa[i]=size[i]=0;
tag=mx=0;
rep(i,L,R)
if (!f[a[i]]) f[a[i]]=fa[i]=i,size[i]=1;
else fa[i]=f[a[i]],++size[fa[i]];
rep(i,L,R) mx=max(mx,a[i]);
}
void modify(int x)
{
if (x>=mx) return;
if (2*x>=mx)
{
rep(i,x+1+tag,mx+tag) if (f[i])
{
int y=i-x;
if (f[y]) fa[f[i]]=f[y],size[f[y]]+=size[f[i]];
else f[y]=f[i],a[f[y]]-=x;
f[i]=0;
}
mx=x;
}
else
{
drep(i,x+tag,1+tag) if (f[i])
{
int y=i+x;
if (f[y]) fa[f[i]]=f[y],size[f[y]]+=size[f[i]];
else f[y]=f[i],a[f[y]]+=x;
f[i]=0;
}
tag+=x;mx-=x;
}
}
inline int query(register int x){return x+tag<sz&&f[x+tag]?size[f[x+tag]]:0;}
}b[S]; void init()
{
blo=sqrt(n);
rep(i,1,n) pos[i]=(i-1)/blo+1;
rep(i,1,pos[n]) b[i].L=i*blo-blo+1,b[i].R=min(n,i*blo),b[i].rebuild();
}
int tmp[sz];
void change_(int l,int r,int x)
{
int p=pos[l],tg=b[p].tag;
rep(i,b[p].L,b[p].R) b[p].f[a[getfa(i)]]=0;
rep(i,b[p].L,b[p].R) tmp[i]=a[getfa(i)]-tg;
rep(i,b[p].L,b[p].R) a[i]=tmp[i];
rep(i,l,r) if (a[i]>x) a[i]-=x;
b[p].rebuild();
}
void change(int l,int r,int x)
{
int pl=pos[l],pr=pos[r];
if (pl==pr) return change_(l,r,x);
change_(l,b[pl].R,x),change_(b[pr].L,r,x);
if (pl==pr+1) return;
++pl,--pr;
rep(i,pl,pr) b[i].modify(x);
}
int query_(int l,int r,int x)
{
int ret=0,p=pos[l],X=b[p].tag+x;
rep(i,l,r)
ret+=(a[getfa(i)]==X);
return ret;
}
int query(int l,int r,int x)
{
int pl=pos[l],pr=pos[r];
if (pl==pr) return query_(l,r,x);
int ret=query_(l,b[pl].R,x)+query_(b[pr].L,r,x);
if (pl+1==pr) return ret;
++pl,--pr;
rep(i,pl,pr) ret+=b[i].query(x);
return ret;
} int main()
{
// file();
// clock_t t=clock();
read(n);read(m);
rep(i,1,n) read(a[i]);
init();
register int z,x,l,r;
rep(_,1,m)
{
read(z);read(l);read(r);read(x);
if (z==1) change(l,r,x);
else print(query(l,r,x));
}
Ot();
// cout<<(clock()-t)/1000.0;
// return 0;
}

洛谷P4117 [Ynoi2018]五彩斑斓的世界 [分块,并查集]的更多相关文章

  1. Solution -「Ynoi 2018」「洛谷 P4117」五彩斑斓的世界

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\),处理 \(m\) 次操作: 给定 \(l,r,x\),把 \([l,r]\) 内所有 \(&g ...

  2. 洛谷P1991无线通讯网[kruskal | 二分答案 并查集]

    题目描述 国防部计划用无线网络连接若干个边防哨所.2 种不同的通讯技术用来搭建无线网络: 每个边防哨所都要配备无线电收发器:有一些哨所还可以增配卫星电话. 任意两个配备了一条卫星电话线路的哨所(两边都 ...

  3. 洛谷 P2024 食物链 POJ 1182 Label:并查集Turbo

    题目描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B 吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的一种,但是我 ...

  4. 洛谷P3402 【模板】可持久化并查集(可持久化线段树,线段树)

    orz TPLY 巨佬,题解讲的挺好的. 这里重点梳理一下思路,做一个小小的补充吧. 写可持久化线段树,叶子节点维护每个位置的fa,利用每次只更新一个节点的特性,每次插入\(logN\)个节点,这一部 ...

  5. [洛谷P2024/POJ1182]食物链 - 带偏移量的并查集(2)

    Description 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的 ...

  6. 货车运输-洛谷-1967-LCA+最大生成树(kruskal(并查集))

    传送门 一道:LCA+最大生成树 个人认为把这两个的板子写好(并熟练掌握了之后)就没什么难的 (但我还是de了好久bug)qwq 最大生成树:其实就是最小生成树的变形 我用的是kruskal (个人觉 ...

  7. 洛谷P4768 [NOI2018]归程(可持久化并查集,最短路)

    闲话 一个蒟蒻,在网络同步赛上进行了这样的表演-- T2组合计数不会,T3字符串数据结构不会,于是爆肝T1 一开始以为整个地图都有车,然后写了2h+的树套树,终于发现样例过不去 然后写可持久化并查集D ...

  8. 洛谷 P1525 【关押罪犯】种类并查集

    题解 P1525 [关押罪犯]:种类并查集 前言: 在数据结构并查集中,种类并查集属于扩展域并查集一类. 比较典型的题目就是:食物链(比本题难一些,有三个种类存在) 首先讲一下本题的贪心,这个是必须要 ...

  9. 洛谷P3402 【模板】可持久化并查集 [主席树,并查集]

    题目传送门 可持久化并查集 n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 ...

随机推荐

  1. [译]MediatR, FluentValidation, and Ninject using Decorators

    原文 CQRS 我是CQRS模式的粉丝.对我来说CQRS能让我有更优雅的实现.它同样也有一些缺点:通常需要更多的类,workflow不总是清晰的. MediatR MediatR的文档非常不错,在这就 ...

  2. luogu 2051 中国象棋

    非常好的dp,锻炼思维 f[i][j][k] 前i行有j列放1,k列放2 #include<bits/stdc++.h> #define int long long #define rep ...

  3. 测试四则运算2:Right-BICEP

    n6个值得测试的具体部位,他们能够提高你的测试技巧 nRight-结果是否正确? nB-是否所有的边界条件都是正确的? nI-能查一下反向关联吗 nC-能用其他手段交叉检查一下结果吗? nE-你是否可 ...

  4. luogu P3250 [HNOI2016]网络

    传送门 考虑只有一个询问,怎么使用暴力枚举最快的得到答案.因为要求最大的,所以可以把链按权值从大往小排序,然后往后扫,找到一个没有交的就是答案,直接退出 一堆询问,可以考虑整体二分,先二分一个值\(m ...

  5. 剑指Offer题解索引

    数组 数组中重复的数字 二维数组中的查找 构建乘积数组 字符串 替换空格 字符流中第一个不重复的字符 表示数值的字符串 递归和循环 斐波那契数列 跳台阶 变态跳台阶 矩形覆盖 链表 从尾到头打印链表 ...

  6. 使用AOP AspectJ 定义@Before,@After ,@Aroud后 执行两次

    背景 转眼之间,发现博客已经将近半年没更新了,甚是惭愧.话不多说,正如标题所言,最近在使用AspectJ的时候,发现拦截器(AOP切面)执行了两次了.我们知道,AspectJ是AOP的一种解决方案,本 ...

  7. E - Emptying the Baltic Kattis - emptyingbaltic (dijkstra堆优化)

    题目链接: E - Emptying the Baltic Kattis - emptyingbaltic 题目大意:n*m的地图, 每个格子有一个海拔高度, 当海拔<0的时候有水. 现在在(x ...

  8. 转:Java项目开发规范参考

    Java项目开发规范参考 - KevinLee的博客 - 博客频道 - CSDN.NEThttp://blog.csdn.net/u011383131/article/details/51227860 ...

  9. jquery禁用a标签

    jquery禁用a标签方法1 01 02 03 04 05 06 07 08 09 10 11 12 $(document).ready(function () {         $("a ...

  10. 20165221 JAVA第二周学习心得及体会

    基本数据类型与数组理论学习 根据第二章的网课链接,归纳出以下板块: 知识框架 标识符与关键字 1.标识符 其本质是文件名字 标识符的第一个字符不能为数字,标识符不能为关键字(如inter) 标识符不能 ...