[Ynoi2018]未来日记
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Ynoi2018]未来日记相关的知识,希望对你有一定的参考价值。
未来日记
题解
干脆叫它君主贞卡常二世吧,这还得带一个君主buff
首先看到 题目名 出题人,我们可以先猜测它是一个分块,考虑怎么分块。
如果你刚好做过 ZQC 的手办 应该很容易想到题解中给出的一种分块做法。
没错,对于每个块,我们记录它前缀中为
x
x
x的数的个数以及前缀中在
b
l
o
c
k
x
block_{x}
blockx中数的个数,查询就直接像线段树一样,枚举找到它第
k
k
k小的值。
先找第
k
k
k小的值所属于的块,再找这个块中对应的值。
记录的是前缀方便我们通过差分找到连续的块中的值。
但修改操作我们该怎么做呢?
对于散块我们就暴力修改,对于整块我们就打上懒标记,然后在块对应的前缀中修改。
但很明显的一点,我们打了懒标记就以为着我们在修改和查询散块时需要将该块懒标记下传后再操作。
我们可以用指针加启发式合并的方式维护懒标记的下传,这就意味着我们对于单块的懒标记下传时间复杂度达到了
O
(
S
l
o
g
S
)
O\\left(Slog\\,S\\right)
O(SlogS)。
我们记数域为
M
M
M,总时间复杂度
O
(
n
(
M
+
m
)
S
+
n
l
o
g
S
+
m
(
M
S
′
+
S
′
+
S
)
)
⩾
O
(
m
m
+
n
m
(
M
+
m
)
)
O\\left(\\frac{n(M+m)}{S}+nlog\\,S+m(\\frac{M}{S'}+S'+S)\\right)\\geqslant O\\left(m\\sqrt{m}+\\sqrt{nm(M+m)}\\right)
O(Sn(M+m)+nlogS+m(S′M+S′+S))⩾O(mm+nm(M+m))。
一个很明显可以过的复杂度 ,但这**lxl竟然卡我常!!!真是不可饶恕。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=1000000000000000000LL;
const int mo=1e9+7;
const int n1=380;
const int n2=100;
const int inv2=499122177;
const int jzm=2333;
const int lim=100000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-7;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
const int M=MAXN/n1+5;
const int N=MAXN/n2+5;
int n,m,a[MAXN],block[MAXN],bk[MAXN],L[M],R[M],bL[N],bR[N],b[MAXN];
int sum[M][MAXN],sm[M][N],tmp[MAXN],tp[N],id[MAXN],stak[M],bl[n1+5];
struct ming{int x,y;}vec[M][MAXN];
int cas[n1+5][n1+5],len[n1+5];
void WorkBlock(int ip){
int tot=0;
for(int i=L[ip];i<=R[ip];i++){
if(!id[a[i]])id[a[i]]=++tot,bl[tot]=a[i];
cas[id[a[i]]][++len[id[a[i]]]]=i;
}
for(int i=1;i<=stak[ip];i++){
ming t=vec[ip][i];if(t.x==t.y||!id[t.x])continue;
if(!id[t.y]){id[t.y]=id[t.x];id[t.x]=0;bl[id[t.y]]=t.y;continue;}
if(len[id[t.x]]>len[id[t.y]])
swap(id[t.x],id[t.y]),bl[id[t.x]]=t.x,bl[id[t.y]]=t.y;
for(int j=1;j<=len[id[t.x]];j++)
cas[id[t.y]][++len[id[t.y]]]=cas[id[t.x]][j];
len[id[t.x]]=0;bl[id[t.x]]=0;id[t.x]=0;
}
for(int i=1;i<=tot;i++){
if(!len[i])continue;
for(int j=1;j<=len[i];j++)a[cas[i][j]]=bl[i];
bl[i]=id[bl[i]]=len[i]=0;
}
stak[ip]=0;
}
signed main(){
read(n);read(m);
for(int i=1;i<=n;i++)read(a[i]),block[i]=(i+n1-1)/n1;
for(int i=1;i<=n;i++){if(!L[block[i]])L[block[i]]=i;R[block[i]]=i;}
for(int i=1;i<=lim;i++)bk[i]=(i+n1-1)/n1;
for(int i=1;i<=lim;i++){if(!bL[bk[i]])bL[bk[i]]=i;bR[bk[i]]=i;}
for(int i=1;i<=block[n];i++){
for(int j=1;j<=lim;j++)sum[i][j]=sum[i-1][j];
for(int j=L[i];j<=R[i];j++)sum[i][a[j]]++;
for(int j=1;j<=lim;j++)sm[i][bk[j]]+=sum[i][j];
}
for(int i=1;i<=m;i++){
int opt,l,r;read(opt);read(l);read(r);
if(opt==1){
int x,y;read(x);read(y);int num=0;
if(block[l]==block[r]){
WorkBlock(block[l]);
for(int j=l;j<=r;j++)if(a[j]==x)a[j]=y,num++;
for(int j=block[l];j<=block[n];j++)
sum[j][x]-=num,sm[j][bk[x]]-=num,
sum[j][y]+=num,sm[j][bk[y]]+=num;
continue;
}
WorkBlock(block[l]);WorkBlock(block[r]);num=0;
for(int j=l;j<=R[block[l]];j++)if(a[j]==x)a[j]=y,num++;
for(int j=block[l];j<block[r];j++)
sum[j][x]-=num,sm[j][bk[x]以上是关于[Ynoi2018]未来日记的主要内容,如果未能解决你的问题,请参考以下文章