是个很有趣的题目,当时比赛的时候我是并没有写出来的
看到赛后出题者发的题解一步一步敲,交了足足几十发
这个是题解
官方题解
这是个最后在队友的debug之下才能ac的弱鸡代码,害,可谓失之毫厘,差之千里了。
写这篇博客的用意也没有什么,只是看到题解虽然写的是主席树解法,但是过的几位巨佬大多数是用线段树过的而且非常快 ,所以发个主席树的写法
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+20;
const int mod = 1000000007;
int T;
int n,m,q;
ll a[maxn],ans[maxn*3];
vector<pair<int,int>>v[maxn];
vector<ll>b;
//树状数组维护最小值
//因为维护的是l的最小值,在使用树状数组的时候倒着来
ll f[maxn];
inline int lowbit(int x) {
return x&(-x);
}
void change(int x, ll val){
for (; x <= n; x += lowbit(x)) f[x] = min(f[x], val);
}
ll find(int x) {
ll res = (1ll << 60);
for(; x ; x -= lowbit(x)) res = min(f[x],res);
return res;
}
//zhu_xi_shu
struct Tree{
int l,r;
int sum;
}tree[maxn*20];
int root[maxn],cnt(0),sz(0); //根标号,根数,数值大小;
int update(int t,int st,int L,int R) {
int nowp = ++cnt; //
tree[nowp].l = tree[st].l; tree[nowp].r = tree[st].r;
tree[nowp].sum = tree[st].sum+1;
if(L == R) return nowp;
int mid = (L+R)>>1;
if(mid >= t) tree[nowp].l = update(t,tree[nowp].l,L,mid);
else tree[nowp].r = update(t,tree[nowp].r,mid+1,R);
return nowp;
}
int query(int l,int r,int k,int L,int R){
if(L == R) return L;
int sum = tree[tree[r].l].sum - tree[tree[l].l].sum;
int mid = (L+R)>>1;
if(k <= sum) return query(tree[l].l,tree[r].l,k,L,mid);
else return query(tree[l].r,tree[r].r,k - sum,mid+1,R);
}
//*******************************
int check(int l,int r,int k1,int k2,int L,int R) { //主席树区间查询
int sum = tree[r].sum - tree[l].sum;
if(k1 <= L && k2 >= R) return sum;
int mid = (L+R)>>1;
if(k2 <= mid) {
return check(tree[l].l,tree[r].l,k1,k2,L,mid);
} else if(k1 > mid){
return check(tree[l].r,tree[r].r,k1,k2,mid+1,R);
} else {
return (check(tree[l].l,tree[r].l,k1,mid,L,mid) + check(tree[l].r,tree[r].r,mid+1,k2,mid+1,R));
}
}
int findmx(int l,int r,int k1,int k2) { //二分查询
int res(0);
if(k1 > k2) return res;
while(l <= r) {
int mid = (l+r)>>1;
if(check(root[mid-1],root[r],k1,k2,1,sz)) {
res = mid;
l = mid+1;
} else {
r = mid-1;
}
}
return res;
}
int t,temp,x; //**************************
int main(){
#ifdef LOCAL
freopen("test1.txt","r",stdin);
// freopen("test2.txt","w",stdout);
#endif
// scanf("%d",&T);
T = 1;
for(int T1 = 1; T1 <= T; T1++){
scanf("%d %d",&n,&q);
for(int i = 1; i <= n; i++) {
scanf("%lld",a+i);
a[i] += a[i-1]; //前缀和
b.push_back(a[i]);
f[i] = (1ll << 60);
}
//**********建主席树*************
sort(b.begin(),b.end());
b.erase(unique(b.begin(),b.end()),b.end()); //离散化
sz = b.size();
for(int i = 1; i <= n; i++) {
t = lower_bound(b.begin(),b.end(),a[i]) - b.begin() + 1;
root[i] = update(t,root[i-1],1,sz);
}
//**********离线询问************
for(int i = 1; i <= q; i++) {
int l,r; scanf("%d %d",&l,&r);
v[r].push_back(make_pair(l,i));
}
//*******右端点升序查询**********
for(int i = 1; i <= n; i++) { //按照题解思路照搬着写的
change(n-i+1,abs(a[i]-a[i-1]));
t = lower_bound(b.begin(),b.end(),a[i]) - b.begin() + 1;
for(x = findmx(1,i-1,1,t); x && x != 1 && a[x] != a[i]; x = findmx(1,x-1,temp,t) ) {
temp = lower_bound(b.begin(),b.end(),(a[x]+a[i])/2) - b.begin() + 1;
temp = max(1,temp-1);
change(n-x,abs(a[i]-a[x]));
}
change(n-x,abs(a[i]-a[x]));
for(x = findmx(1,i-1,t,sz); x && x != 1 && a[x] != a[i]; x = findmx(1,x-1,t,temp)) {
temp = lower_bound(b.begin(),b.end(),(a[x]+a[i])/2) - b.begin() + 1;
change(n-x,abs(a[i]-a[x]));
}
change(n-x,abs(a[i]-a[x]));
for(int j = 0; j < v[i].size(); j++) {
int l = v[i][j].first, id = v[i][j].second;
ans[id] = find(n-l+1);
}
}
for(int i = 1; i <= q; i++) {
printf("%lld\n",ans[i]);
}
}
return 0;
}