6 1 3 1 1 2 2 3 2 1 2 2 3 5 2 2 1 4 4
3 2 3
这题看起来一副非常厉害的样子。。其实是大水题。
对于一个询问,考虑这个询问前第i 次修改操作,那么这次修改操作出现在序列中第一个位置是2i?1 。然后在询问范围内最多只有60 个数,暴力大法好就好了,时间复杂度O(nlogR) ,R 是询问的最大下标。
ps:自己模拟一下就会发现,对第i个要插入的数,在整个区间内插入的数的数量是2^(i-1)个,并且在[1,R]内也满足,后一个数插入的数的数量一定是前一个插入数的2倍,或2倍+1,知道这个后,[L,R]=[1,R]-[1,L-1],于是sum[i]+=v*(x+1)/2;在[1,R]中v为1,在[1,L-1]中v为-1,此时的i的顺序与插入顺序相反。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=110000; int a[maxn],b[maxn]; long long sum[maxn]; int len=69; void digt(long long x,int v) { int i=0; while(x) { sum[i]+=v*(x+1)/2; x=x/2; i++; } } bool cmp(int x,int y) { return a[len-x]<a[len-y]; } int main() { int t,op; scanf("%d",&t); long long l,r,k,ans; while(t--) { scanf("%d",&op); if(op==1) { scanf("%d",&a[++len]); } else { scanf("%I64d%I64d%I64d",&l,&r,&k); for(int i=0;i<=100;i++) sum[i]=0; digt(r,1); digt(l-1,-1); for(int i=0;i<=69;i++) b[i]=i; sort(b,b+70,cmp); ans=0; for(int i=0;i<70;i++) { // cout<<i<<" "<<sum[b[i]]<<endl; if(ans+sum[b[i]]>=k) { printf("%d\n",a[len-b[i]]); break; } else { ans+=sum[b[i]]; } } } } return 0; }
hdu 5204 Rikka with sequence(BestCoder Round #37)
原文地址:http://blog.csdn.net/caduca/article/details/45027461