「题解」洛谷 P4062 [Code+#1]Yazid 的新生舞会 线性做法
还是考虑那个众数的套路,考虑一个数 \(c\) 的贡献,将 \(c\) 置为 \(1\),不是 \(c\) 的置为 \(-1\),那么一个区间和 \(>0\) 的绝对众数是 \(c\).
从左往右和从右往左各跑一边,每次让一个 \(+1\) 匹配左边第一个没匹配的 \(-1\) (没有的话就匹配到虚空),如果一个位置从前往后或者从后往前都没匹配到,意味着它不可能和其他位置组成逆序对,这个位置就会寄掉,用并查集即可完成匹配。
跑出了这些绝对众数可能为 \(c\) 的连续段,这些连续段的总长度至多是 \(c\) 出现次数的两倍,所以所有 \(c\) 的若干连续段的总长是 \(\mathcal{O}(n)\) 的。
那么作前缀和,在每个连续段内对答案的贡献就是一个二维数点的形式。
注意到相邻数只会有 \(\pm 1\) 的改变,那么扫描线的时候,考虑计算这一个位置统计的答案和上一个位置的差值是多少即可,只需要开个桶记录一下每个值的出现次数。
如果使用线性序列并查集算法,复杂度是 \(\mathcal{O}(n)\) 的,不过写这篇题解的时候用纯路径压缩跑到了洛谷上第一。
找出极长连续段的实现上需要精细一点,可能要双指针什么的(
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<random>
#define pb emplace_back
#define mp std::make_pair
#define fi first
#define se second
#define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<<x<<'\n';
#define dpi(x,y) cerr<<"In Line "<<__LINE__<<" the "<<#x<<" = "<<x<<" ; "<<"the "<<#y<<" = "<<y<<'\n';
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef pair<ll,int>pli;
typedef pair<ll,ll>pll;
typedef vector<int>vi;
typedef vector<ll>vll;
typedef vector<pii>vpii;
inline void cmax(int &x, int y){x=x>y?x:y;}
inline void cmin(int &x, int y){x=x<y?x:y;}
#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 void read(int &r){
r=0;bool w=0;char ch=getchar();
while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar();
while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar();
r=w?-r:r;
}
const int N=500100;
int n,type;
int a[N],L[N],R[N],visbuf[N<<1],*vis=visbuf+N;
vi vec[N];
ll ans;
int f[N],p[N];
int st[N],top;
int getfa1(int x){
return f[x]==x?x:f[x]=getfa1(f[x]);
}
void merge1(int x,int y){
int fx=getfa1(x),fy=getfa1(y);
f[fy]=fx;
}
int getfa2(int x){
return p[x]==x?x:p[x]=getfa2(p[x]);
}
void merge2(int x,int y){
int fx=getfa2(x),fy=getfa2(y);
p[fy]=fx;
}
signed main(){
read(n);read(type);
for(int i=1;i<=n;i++)read(a[i]),p[i]=f[i]=i,vec[a[i]].pb(i);
p[n+1]=f[n+1]=n+1;
for(int o=0;o<n;o++){
int mn=n+1;top=0;
for(auto i:vec[o]){
int fa=getfa1(i-1);
merge1(fa,i);
if(fa)merge1(fa-1,fa);
L[i]=fa;
while(top&&st[top]>fa)--top;
st[++top]=fa;
}
reverse(vec[o].begin(),vec[o].end());
for(auto i:vec[o]){
int fa=getfa2(i+1);
merge2(fa,i);
if(fa<=n)merge2(fa+1,fa);
cmax(R[L[i]],fa);
}
reverse(vec[o].begin(),vec[o].end());
for(int k=1;k<=top;k++){
int l=st[k],r=R[l];
while(l<=r){
++l;cmax(r,R[l]);
}
l=st[k];cmin(r,n);
int cnt=0,s=0;
for(int i=l;i<=r;i++){
L[i]=R[i]=0;f[i]=p[i]=i;
if(i){
if(a[i]==o)cnt+=vis[s++];
if(a[i]!=o)cnt-=vis[--s];
}
++vis[s];
ans+=cnt;
}
s=0;
for(int i=l;i<=r;i++){
if(i){
if(a[i]==o)++s;
if(a[i]!=o)--s;
}
vis[s]=0;
}
while(k<=top&&st[k]<=r)
++k;
--k;
}
#undef now
}
cout << ans << '\n';
return 0;
}