n<=500000的数字,问有多少个区间的众数出现次数严格大于区间长度的一半。
这么说来一个区间就一个众数了,所以第一反应是枚举数字,对下标进行处理。然后没有第二反应。很好。
在枚举一个数字的时候,可以把这个数字出现的位置记+1,没出现的位置记-1,实际就是问现在这个数组有多少个区间和>0,就是问对每个前缀和Si有多少Sj<Si。
出现的位置加起来总共只有n个,如果-1的那些区间能够进行区间处理该多好啊!
那就维护一个以Si的值为下标的东西,然后查一个区间的答案就是查:
红色部分。也就是要查一个区间和乘上若干,以及一个区间每个数乘上等差数列。可以通过维护每个Si的值的个数的区间和,以及区间Cnt_i * i的和。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdlib.h> 5 //#include<bitset> 6 #include<queue> 7 //#include<math.h> 8 //#include<time.h> 9 //#include<iostream> 10 using namespace std; 11 12 int n,type; 13 #define maxn 1000011 14 #define LL long long 15 struct Node 16 { 17 int id,v; 18 bool operator < (const Node &b) const {return v<b.v || (v==b.v && id<b.id);} 19 }a[maxn]; 20 int lisan[maxn],li=0; 21 22 const int most=1000006; 23 struct SMT 24 { 25 struct Node 26 { 27 int ls,rs; 28 int sum;LL sss; 29 int add; 30 }a[maxn<<1]; 31 int size,root; 32 void clear() {size=root=0;} 33 int ql,qr,v; 34 void up(int x) 35 { 36 const int &p=a[x].ls,&q=a[x].rs; 37 a[x].sum=a[p].sum+a[q].sum; 38 a[x].sss=a[p].sss+a[q].sss; 39 } 40 void New(int &x) 41 { 42 x=++size; a[x].ls=a[x].rs=0; 43 a[x].sss=a[x].add=a[x].sum=0; 44 } 45 void addsingle(int x,int L,int R,int v) 46 { 47 a[x].sum+=(R-L+1)*v; 48 a[x].sss+=((1ll*(most-R+1+most-L+1)*(R-L+1))>>1)*v; 49 a[x].add+=v; 50 } 51 void down(int x,int L,int R) 52 { 53 int &p=a[x].ls,&q=a[x].rs,mid=(L+R)>>1; 54 if (!p) New(p); if (!q) New(q); 55 if (a[x].add) 56 { 57 addsingle(p,L,mid+0,a[x].add); 58 addsingle(q,mid+1,R,a[x].add); 59 a[x].add=0; 60 } 61 } 62 void Add(int &x,int L,int R) 63 { 64 if (!x) New(x); 65 if (ql<=L && R<=qr) {addsingle(x,L,R,v); return;} 66 down(x,L,R); 67 const int mid=(L+R)>>1; 68 if (ql<=mid) Add(a[x].ls,L,0+mid); 69 if (qr> mid) Add(a[x].rs,mid+1,R); 70 up(x); 71 } 72 void add(int L,int R,int v) 73 { 74 if (L>R) return; 75 L+=most>>1; R+=most>>1; 76 this->v=v; ql=L; qr=R; 77 Add(root,1,most); 78 } 79 LL Querysum(int &x,int L,int R) 80 { 81 if (!x) New(x); 82 if (ql<=L && R<=qr) return a[x].sum; 83 down(x,L,R); 84 const int mid=(L+R)>>1; LL ans=0; 85 if (ql<=mid) ans+=Querysum(a[x].ls,L,mid); 86 if (qr> mid) ans+=Querysum(a[x].rs,mid+1,R); 87 return ans; 88 } 89 LL querysum(int L,int R) 90 { 91 if (L>R) return 0; 92 L+=most>>1; R+=most>>1; 93 ql=L; qr=R; 94 return Querysum(root,1,most); 95 } 96 LL Querysss(int &x,int L,int R) 97 { 98 if (!x) New(x); 99 if (ql<=L && R<=qr) return a[x].sss; 100 down(x,L,R); 101 const int mid=(L+R)>>1; LL ans=0; 102 if (ql<=mid) ans+=Querysss(a[x].ls,L,mid); 103 if (qr> mid) ans+=Querysss(a[x].rs,mid+1,R); 104 return ans; 105 } 106 LL querysss(int L,int R) 107 { 108 if (L>R) return 0; 109 L+=most>>1; R+=most>>1; 110 ql=L; qr=R; 111 return Querysss(root,1,most); 112 } 113 }t; 114 115 int main() 116 { 117 scanf("%d%d",&n,&type); 118 for (int i=1;i<=n;i++) scanf("%d",&a[i].v),a[i].id=i; 119 sort(a+1,a+1+n); a[n+1].v=0x3f3f3f3f; 120 121 LL ans=0; 122 for (int i=2,j=1;i<=n+1;i++) if (a[i].v!=a[i-1].v) 123 { 124 t.clear(); 125 int last=0,where=0; 126 t.add(0,0,1); 127 for (;j<i;j++) 128 { 129 const int now=a[j].id; 130 if (now-last>1) 131 { 132 int len=now-last-1; 133 ans+=t.querysss(where-len-1,where-2)+t.querysum(1-(most>>1),where-len-2)*len 134 -t.querysum(where-len-1,where-2)*(most-where-(most>>1)+2); 135 t.add(where-len,where-1,1); 136 where-=len; 137 } 138 ans+=t.querysum(1-(most>>1),where); 139 where++; t.add(where,where,1); 140 last=now; 141 } 142 int len=n-last; 143 (len)&&(ans+=t.querysss(where-len-1,where-2)+t.querysum(1-(most>>1),where-len-2)*len 144 -t.querysum(where-len-1,where-2)*(most-where-(most>>1)+2)); 145 } 146 printf("%lld ",ans); 147 return 0; 148 }
这题还有树状数组和分治的写法。待填坑。