Codeforces Global Round 2 D. Frets On Fire (动态开点线段树,沙雕写法)

时间:2021-07-14 06:23:57

题目链接:D. Frets On Fire

思路:明明可以离散化+二分写,思路硬是歪到了线段树上,自闭了,真实弟弟,怪不得其他人过得那么快

只和查询的区间长度有关系,排完序如果相邻的两个点的差值小于等于查询的区间长度,那么给结果带来的变化就会新增差值个数,如果大于区间长度那么就会新增区间长度个数

维护的话,线段树和二分都可以,二分需要离散化处理,再给差值排个序,每次找到第一个大于当前区间长度的差值位置就好了,(没实现,但是理论上应该没问题)

线段树直接动态开点可以不用离散化。。

实现代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mid ll m = (l + r) /2
const ll M = 1e5+;
#define ROF(i,a,b) for(ll i=a;i>=b;i--)
ll sum[M*],num[M*];
ll ls[M*],rs[M*];
ll idx;
void update(ll p,ll c,ll l,ll r,ll &rt){
if(!rt) rt = ++idx;
sum[rt] += c;
num[rt] += ;
if(l == r){
return ;
}
mid;
if(p <= m) update(p,c,l,m,ls[rt]);
else update(p,c,m+,r,rs[rt]);
} ll query(ll L,ll R,ll l,ll r,ll rt){
if(L <= l&&R >= r){
return sum[rt];
}
mid;
ll ret = ;
if(L <= m) ret += query(L,R,l,m,ls[rt]);
if(R > m) ret += query(L,R,m+,r,rs[rt]);
return ret;
} ll ask(ll L,ll R,ll l,ll r,int rt){
if(L <= l&&R >= r){
return num[rt];
}
mid;
ll ret = ;
if(L <= m) ret += ask(L,R,l,m,ls[rt]);
if(R > m) ret += ask(L,R,m+,r,rs[rt]);
return ret;
}
ll a[*M];
int main()
{
ll n,m,x,y,rt = ;
scanf("%lld",&n);
for(ll i = ;i <= n;i ++){
scanf("%lld",&a[i]);
}
sort(a+,a++n);
for(ll i = ;i <= n;i ++){
ll num = a[i] - a[i-];
update(num,num,,1e18,rt);
}
scanf("%lld",&m);
for(ll i = ;i <= m;i ++){
scanf("%lld%lld",&x,&y);
ll num = y-x+;
ll ans = num;
ans += query(,num,,1e18,rt);
//cout<<ans<<" ";
ans += ask(num+,1e18,,1e18,rt)*num;
printf("%lld\n",ans);
}
}