先考虑部分分(只有01/只有0~7)做法:枚举每个数,把和他相同的设为1,不同的设为-1,然后这个数作为众数贡献的个数就是区间和>0的个数
推着做,树状数组记前缀和<=x的区间的数量就可以,复杂度$O(8nlogn)$
如果直接套过来,$O(n^2logn)$肯定是不行的,但可以发现枚举了所有数以后1的个数一共只能有n个,而如果把相邻的-1看成一个,它的数量也是O(n)的
所以对于1的做法是不变的;对于-1,我们要连起来处理。如果设这段-1之前的和为sum,-1的个数为len可以得到这段-1的贡献,其实就是$[-n,sum-len-1]+[-n,sum-len]+...+[-n,sum-2]$(我们用一个权值线段树来记前缀和为某值的数量)
为了方便计算,做一个前缀和,就变成了
$$sumlimits_{i=-n}^{sum-2}{sumlimits_{j=-n}^{i}{a[j]}}-sumlimits_{i=-n}^{sum-len-2}{sumlimits_{j=-n}^{i}{a[j]}}$$
(可以看出与树状数组做区间加、区间求和的操作类似)
$$=(sum-2+1)sumlimits_{i=-n}^{sum-2}{a[i]}-sumlimits_{i=-n}^{sum-2}{i*a[i]}-((sum-len-2+1)sumlimits_{i=-n}^{sum-len-2}{a[i]}-sumlimits_{i=-n}^{sum-len-2}{i*a[i]})$$
然后用线段树维护a[i]和i*a[i]就可以了。而且我们每次枚举完一个以后不能直接memset,不然就变成O(n^2)了,要怎么加进来的就怎么减回去..
(然后我bzoj上就T了,肯定是评测机太卡了)
1 #define __Ressed__ <bits/stdc++.h> 2 #include __Ressed__ 3 #define pa pair<int,int> 4 #define lowb(x) ((x)&(-(x))) 5 #define REP(i,n0,n) for(i=n0;i<=n;i++) 6 #define PER(i,n0,n) for(i=n;i>=n0;i--) 7 #define MAX(a,b) ((a>b)?a:b) 8 #define MIN(a,b) ((a<b)?a:b) 9 #define CLR(a,x) memset(a,x,sizeof(a)) 10 #define rei register int 11 using namespace std; 12 typedef long long ll; 13 const int maxn=5e5+5; 14 15 inline ll rd(){ 16 ll x=0;char c=getchar();int neg=1; 17 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 18 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 19 return x*neg; 20 } 21 22 ll v[maxn*4],iv[maxn*4],laz[maxn*4],ans; 23 int ch[maxn*4][2],pct,root; 24 int nxt[maxn],hd[maxn]; 25 int L,N,M,num[maxn],tmp[maxn]; 26 27 inline void pushdown(int p,int l,int r){ 28 int m=l+r>>1,a=ch[p][0],b=ch[p][1]; 29 if(a){ 30 laz[a]+=laz[p]; 31 v[a]+=laz[p]*(m-l+1); 32 iv[a]+=laz[p]*(m+l)*(m-l+1)/2; 33 } 34 if(b){ 35 laz[b]+=laz[p]; 36 v[b]+=laz[p]*(r-m); 37 iv[b]+=laz[p]*(r+m+1)*(r-m)/2; 38 } 39 laz[p]=0; 40 } 41 42 inline void update(int p){ 43 v[p]=v[ch[p][0]]+v[ch[p][1]]; 44 iv[p]=iv[ch[p][0]]+iv[ch[p][1]]; 45 } 46 47 void build(int &p,int l,int r){ 48 if(!p) p=++pct; 49 if(l<r){ 50 int m=l+r>>1; 51 build(ch[p][0],l,m); 52 build(ch[p][1],m+1,r); 53 } 54 } 55 56 inline void add(int p,int l,int r,int x){ 57 laz[p]+=x; 58 v[p]+=1ll*(r-l+1)*x; 59 iv[p]+=1ll*(r+l)*(r-l+1)/2*x; 60 pushdown(p,l,r); 61 } 62 63 void ins(int p,int l,int r,int x,int y,int z){ 64 if(x<=l&&r<=y){ 65 add(p,l,r,z); 66 }else{ 67 pushdown(p,l,r); 68 int m=l+r>>1; 69 if(x<=m) ins(ch[p][0],l,m,x,y,z); 70 if(y>=m+1) ins(ch[p][1],m+1,r,x,y,z); 71 update(p); 72 } 73 } 74 75 ll query(int p,int l,int r,int x){ 76 pushdown(p,l,r); 77 if(r<=x){ 78 return v[p]*(x+1)-iv[p]; 79 }else{ 80 int m=l+r>>1;ll re; 81 re=query(ch[p][0],l,m,x); 82 if(x>=m+1) re+=query(ch[p][1],m+1,r,x); 83 return re; 84 } 85 } 86 87 ll query2(int p,int l,int r,int x){ 88 if(r<=x){ 89 return v[p]; 90 }else{ 91 pushdown(p,l,r); 92 int m=l+r>>1;ll re; 93 re=query2(ch[p][0],l,m,x); 94 if(x>=m+1) re+=query2(ch[p][1],m+1,r,x); 95 return re; 96 } 97 } 98 99 int main(){ 100 // freopen("6253.in","r",stdin); 101 rei i,j,k; 102 N=rd();rd(); 103 for(i=1;i<=N;i++) tmp[i]=num[i]=rd(); 104 sort(tmp+1,tmp+N+1);M=unique(tmp+1,tmp+N+1)-tmp-1; 105 for(i=1;i<=N;i++) num[i]=lower_bound(tmp+1,tmp+M+1,num[i])-tmp; 106 for(i=N;i;i--){ 107 nxt[i]=hd[num[i]];hd[num[i]]=i; 108 } 109 L=N+1; 110 build(root,-L,L); 111 ins(root,-L,L,0,0,1); 112 for(i=1;i<=M;i++){ 113 int sum=0; 114 for(j=hd[i],k=1;j;j=nxt[j]){ 115 if(k<j){ 116 ans+=query(root,-L,L,sum-2)-query(root,-L,L,sum-j+k-2); 117 ins(root,-L,L,sum-j+k,sum-1,1); 118 sum-=j-k; 119 }sum++; 120 ans+=query2(root,-L,L,sum-1); 121 ins(root,-L,L,sum,sum,1); 122 k=j+1; 123 } 124 ans+=query(root,-L,L,sum-2)-query(root,-L,L,sum-N+k-3); 125 sum=0; 126 for(j=hd[i],k=1;j;j=nxt[j]){ 127 if(k<j){ 128 ins(root,-L,L,sum-j+k,sum-1,-1); 129 sum-=j-k; 130 }sum++; 131 ins(root,-L,L,sum,sum,-1); 132 k=j+1; 133 } 134 } 135 printf("%lld ",ans); 136 return 0; 137 }