NOIP模拟题 2015.8.2 T3
HJWJBSR
posted @ 2015年8月16日 22:16
in 题解
, 577 阅读
题解:有一个暴力是将r-l+1个数排序之后从小到大加,设已经加的数的和为s,当前要加ai,如果s<ai-1则不能加s(然而这个我在考场上面都没想到)于是正解就是优化一下,考虑每次加数把可以加的都加进来,于是s每次扩大一倍,至于加哪些数可以用主席树,复杂度为n log^2 n。
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 100050
#define M 1073741824
int gf[N],st=0,s[N*50],c[N*50][2],v[N],n,m;
inline int Read()
{
int x=0;char y;
do y=getchar(); while (y<'0'||y>'9');
do x=x*10+y-'0',y=getchar(); while (y>='0'&&y<='9');
return x;
}
int Set_up(int x,int y,int z,int o)
{
int i=x + y >> 1,j=++st;
if (x==y) {s[j]=s[z]+o;return j;}
if (o<=i) c[j][1]=c[z][1],c[j][0]=Set_up(x,i,c[z][0],o);else
c[j][0]=c[z][0],c[j][1]=Set_up(i+1,y,c[z][1],o);
s[j]=s[c[j][0]]+s[c[j][1]];
return j;
}
int Find(int x,int y,int z,int o,int p,int u)
{
int i=x + y >> 1,j=0;
if (x==p&&y==u) return s[o]-s[z];
if (p<=i) j=Find(x,i,c[z][0],c[o][0],p,min(u,i));
if (u>i) j+=Find(i+1,y,c[z][1],c[o][1],max(p,i+1),u);
return j;
}
int Solve(int y,int x)
{
int k=0,l=0,q=0;
do
{
l=Find(0,M-1,gf[x-1],gf[y],q+1,k+1);
if (!l) return k+1;
q=k+1;k=k+l;
} while (1);
}
int main()
{
freopen("hhsum.in","r",stdin);
freopen("hhsum.out","w",stdout);
n=Read();
for (int i=1;i<=n;i++) v[i]=Read();
for (int i=1;i<=n;i++)
gf[i]=Set_up(0,M-1,gf[i-1],v[i]);
m=Read();
while (m--)
printf("%d\n",Solve(Read(),Read()));
return 0;
}
评论 (0)