P4119 [Ynoi2018] 未来日记 题解
最初分块,个人感觉如果之前做过带插入区间
思路#
由于要询问的是区间第
具体的,我们对于序列上的每一个块维护两个数组。
第一个是每个数对于每个块的前缀和。
第二个是对第一个数组进行的分块。
所以对于一个区间的第
找到之后,再在块中扫一遍。
由于最多只有
所以时间复杂度
我们现在来考虑如何实现修改:
把区间
如果做过第二分块的话就可以想到用并查集处理这个问题。
对于散块,我们直接重构出整个块的并查集关系。
由于改变的只有
我们暴力统计更改后出这一块内
所以时间复杂度为
至于整块,我们可以对于每一个块直接更改并查集,由于最多
所以时间复杂度为
总时间复杂度
但这个代码还不足以通过此题,你只能获得
我们发现如果是左右端点不同块的修改,对于散块需要有两倍的常数,所以我们考虑对散块进行进一步的优化。
由于在散块内并查集更改的只有权值为
所以我们只更改他们的并查集关系,不直接重构整块。
时间复杂度不变,但足以通过此题了。
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
const int len = 430;
const int bas = 100000;
int n , m , top , a[N] , s[N] , h[N] , q[N] , l[N] , r[N] , ch[N] , fa[N] , pos[N] , stk[N];
struct Node
{
int a[N] , ton[N] , siz[len + 10];
}b[len + 100];
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
inline int read()
{
int asd = 0 , qwe = 1; char zxc;
while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
return asd * qwe;
}
inline int gf(int x)
{
return fa[x] == x ? x : fa[x] = gf(fa[x]);
}
inline int merge(int x , int y , int pos)
{
if(b[pos].ton[y]) fa[b[pos].ton[x]] = b[pos].ton[y];
else b[pos].ton[y] = b[pos].ton[x] , s[b[pos].ton[x]] = y;
b[pos].ton[x] = 0; return b[pos].a[x] - b[pos - 1].a[x];
}
inline void update(int x , int y , int ls , int rs)
{
int posl = pos[ls] , res = 0; top = 0;
b[posl].ton[x] = b[posl].ton[y] = 0;
for(int i = l[posl];i <= min(r[posl] , n);i++)
{
a[i] = s[gf(i)];
if(a[i] == x || a[i] == y) stk[++top] = i;
}
for(int i = ls;i <= rs;i++)
if(a[i] == x) res++ , a[i] = y;
for(int i = 1;i <= top;i++)
{
int j = stk[i];
if(!b[posl].ton[a[j]]) b[posl].ton[a[j]] = fa[j] = j , s[j] = a[j];
else fa[j] = b[posl].ton[a[j]];
}
for(int i = posl;i <= pos[n];i++)
b[i].siz[pos[x]] -= res , b[i].a[x] -= res,
b[i].siz[pos[y]] += res , b[i].a[y] += res;
}
inline void delet(int x) { h[x]-- , q[pos[x]]--; }
inline void insert(int x) { h[x]++ , q[pos[x]]++; }
int main()
{
int fir = 0;
n = read() , m = read();
for(int i = 1;i <= bas;i++) pos[i] = (i - 1) / len + 1 , r[pos[i]] = i;
for(int i = 1;i <= bas;i++) l[pos[i]] = (l[pos[i]] ? l[pos[i]] : i);
for(int i = 1;i <= n;i++) a[i] = read();
for(int i = 1;i <= pos[n];i++)
for(int j = l[i];j <= min(r[i] , n);j++)
b[i].a[a[j]]++ , b[i].siz[pos[a[j]]]++;
for(int i = 1;i <= pos[n];i++)
for(int j = l[i];j <= min(r[i] , n);j++)
if(!b[i].ton[a[j]]) b[i].ton[a[j]] = fa[j] = j , s[j] = a[j];
else fa[j] = b[i].ton[a[j]];
for(int i = 1;i <= pos[n];i++)
{
for(int j = 1;j <= bas;j++)
b[i].a[j] += b[i - 1].a[j];
for(int j = 1;j <= pos[bas];j++)
b[i].siz[j] += b[i - 1].siz[j];
}
for(int o = 1;o <= m;o++)
{
int opt = read();
if(opt == 1)
{
int ls = read() , rs = read() , x = read() , y = read();
if(x == y) continue;
if(pos[ls] == pos[rs]) update(x , y , ls , rs);
else
{
int res = 0;
update(x , y , ls , r[pos[ls]]) , update(x , y , l[pos[rs]] , rs);
for(int i = pos[ls] + 1;i <= pos[rs] - 1;i++)
ch[i] = merge(x , y , i);
for(int i = pos[ls] + 1;i <= pos[rs] - 1;i++)
res += ch[i] , b[i].a[x] -= res , b[i].a[y] += res,
b[i].siz[pos[x]] -= res , b[i].siz[pos[y]] += res;
for(int i = pos[rs];i <= pos[n];i++)
b[i].a[x] -= res , b[i].a[y] += res,
b[i].siz[pos[x]] -= res , b[i].siz[pos[y]] += res;
}
}
if(opt == 2)
{
int ls = read() , rs = read() , k = read() , now = 1 , res;
if(pos[ls] == pos[rs])
{
for(int i = ls;i <= rs;i++)
{
insert(s[gf(i)]);
}
for(int i = 1;i <= pos[bas];i++)
if(k <= q[i]) break;
else k -= q[i] , now++;
for(int i = l[now];i <= r[now];i++)
if(k <= h[i]) { res = i; break; }
else k -= h[i];
for(int i = ls;i <= rs;i++) delet(s[gf(i)]);
}
else
{
int bl = pos[ls] , br = pos[rs] - 1;
for(int i = ls;i <= r[pos[ls]];i++) insert(s[gf(i)]);
for(int i = l[pos[rs]];i <= rs;i++) insert(s[gf(i)]);
for(int i = 1;i <= pos[bas];i++)
if(k <= q[i] + b[br].siz[i] - b[bl].siz[i]) break;
else k -= q[i] + b[br].siz[i] - b[bl].siz[i] , now++;
for(int i = l[now];i <= r[now];i++)
if(k <= h[i] + b[br].a[i] - b[bl].a[i]) { res = i; break; }
else k -= h[i] + b[br].a[i] - b[bl].a[i];
for(int i = ls;i <= r[pos[ls]];i++) delet(s[gf(i)]);
for(int i = l[pos[rs]];i <= rs;i++) delet(s[gf(i)]);
}
printf("%d\n" , res);
}
}
return 0;
}
作者:JiaY19
出处:https://www.cnblogs.com/JiaY19/p/16055829.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)