https://codeforces.com/contest/1288/problem/E
莫队做的这题,根号常数慌得一匹,加了一堆常数优化,最后1081ms,怕被hack,最后主席树没冲出来,结果这题没被hack,A,D没了,艹,本来可以上波大分结果变成掉分。
下面的代码是没加优化前的,赛后测了一下是1949ms,差了将近一倍。。。。
很显然最前面要么是一开始的位置,要么是后面有message被调到第一位。
最后面那就是在调到第一位之后,在下次被调到第一位之前,有多少不同的数字。
可以在输入的数据前加上n n-1 n-2.....2 1,变成一个n+m的序列,方便处理。
区间不同的数字,强制在线的话可以用主席树,没到一个位置,就开一个rt把这个数字上次出现的位置删掉,再开一个rt把这个数字这次出现的位置+1,没强制在线的话可以直接莫队,我就莫队了(其实是忘记主席树可以写了,最后主席树WA9了没冲出来
看了牛逼网友的代码,由于这题可以从左到右或者从右到做按顺序求区间不同数字个数,所以树状数组也可以做,我太菜了.jpg,总是用复杂方法。。。
#include<bits/stdc++.h>
#define maxl 600010
using namespace std;
int n,m,ans,tot,sz,res;
int a[maxl],last[maxl],ansl[maxl],ansr[maxl],sum[maxl];
char s[maxl];
struct que
{
int l,r,id;
}q[maxl];
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
ansl[i]=i,ansr[i]=i;
last[i]=n+m+1,a[i]=n-i+1;
}
for(int i=n+1;i<=n+m;i++)
{
scanf("%d",&a[i]);
ansl[a[i]]=1;
}
m=n+m;
tot=0;
for(int i=m;i>=1;i--)
{
if(i+1<=last[a[i]]-1)
q[++tot]=que{i+1,last[a[i]]-1,a[i]};
last[a[i]]=i;
}
}
inline bool cmp(const que &a,const que &b)
{
if(a.l/sz==b.l/sz)
return (a.r<b.r);
return a.l/sz<b.l/sz;
}
inline void add(int ind)
{
if(sum[a[ind]]==0)
res++;
sum[a[ind]]++;
}
inline void del(int ind)
{
if(sum[a[ind]]==1)
res--;
sum[a[ind]]--;
}
inline void mainwork()
{
sz=sqrt(tot);
sort(q+1,q+1+tot,cmp);
int left=1,right=0;res=0;
for(int i=1;i<=tot;i++)
{
while(right<q[i].r)
right++,add(right);
while(right>q[i].r)
del(right),right--;
while(left<q[i].l)
del(left),left++;
while(left>q[i].l)
left--,add(left);
ansr[q[i].id]=max(ansr[q[i].id],res+1);
}
}
inline void print()
{
for(int i=1;i<=n;i++)
printf("%d %d\n",ansl[i],ansr[i]);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}