题解 CF1172F 【Nauuo and Bug】
搞一棵线段树
对于一个区间
怎么合并信息?设左面减去了
什么样的
对于一对合法的
具体如何合并呢?这里其他两篇题解说的是有问题的,光是
如何证明?由于
为什么 3 -10000,
另外对于@Ynoi 程序中,第一个 if(y != 0) y --; 其实是挺令人迷惑的,这个其实只是因为如果 y--,所以才有了第一个 if(y != 0) y --;,其实可以写成 if(y>c[rc].n) y--;这样可能好理解一些
对于查询,找最后一个小于等于当前初始值的
时间复杂度:
//timeuse:40min
const int N = 1000010;
int n,m;ll p,a[N];
struct tree { int l,r,len;ll sum;vector<ll> c; }t[N << 2];
#define ls now << 1
#define rs now << 1 | 1
void pushup(int now)
{
t[now].sum = t[ls].sum + t[rs].sum;
int y = 0;
for(int x = 0;x <= t[ls].len;x++)
{
if(y > t[rs].len) y--;
for(;y <= t[rs].len;y++)
{
ll res = t[rs].c[y] + x * p - t[ls].sum;
ll maxx = t[ls].c[x + 1] - 1 - x * p + t[ls].sum;
if(maxx < t[rs].c[y]) { if(y) y--;break; }
t[now].c[x + y] = min(t[now].c[x + y],max(t[ls].c[x],res));
}
}
}
void build(int now,int l,int r)
{
t[now].l = l,t[now].r = r,t[now].len = r - l + 1;
for(int i = 1;i <= t[now].len + 2;i++) t[now].c.push_back(LINF);
t[now].c[0] = -LINF;
if(l == r) { t[now].sum = a[l],t[now].c[1] = p - a[l];return; }
int mid = l + r >> 1;build(ls,l,mid),build(rs,mid + 1,r);
pushup(now);
}
ll query(int now,int l,int r,ll x)
{
if(t[now].l == l && t[now].r == r)
{
ll pos = upper_bound(t[now].c.begin(),t[now].c.end(),x) - t[now].c.begin() - 1;
return x + t[now].sum - p * pos;
}
int mid = t[now].l + t[now].r >> 1;
if(r <= mid) return query(ls,l,r,x);
if(l > mid) return query(rs,l,r,x);
return query(rs,mid + 1,r,query(ls,l,mid,x));
}
int main()
{
n = read(),m = read(),p = read();
for(int i = 1;i <= n;i++) a[i] = read();
build(1,1,n);
while(m--) { int l = read(),r = read();fprint(query(1,l,r,0)); }
return 0;
}