1. 程式人生 > >Codeforces Global Round 2 D. Frets On Fire (動態開點線段樹,沙雕寫法)

Codeforces Global Round 2 D. Frets On Fire (動態開點線段樹,沙雕寫法)

每次 ces code 線段樹 sort 弟弟 turn pda out

題目鏈接: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+10; #define ROF(i,a,b) for(ll i=a;i>=b;i--) ll sum[M*40],num[M*40]; ll ls[M*40],rs[M*40]; ll idx; void update(ll p,ll c,ll l,ll r,ll &rt){ if(!rt) rt = ++idx; sum[rt] += c; num[rt] += 1; if(l == r){
return ; } mid; if(p <= m) update(p,c,l,m,ls[rt]); else update(p,c,m+1,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 = 0; if(L <= m) ret += query(L,R,l,m,ls[rt]); if
(R > m) ret += query(L,R,m+1,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 = 0; if(L <= m) ret += ask(L,R,l,m,ls[rt]); if(R > m) ret += ask(L,R,m+1,r,rs[rt]); return ret; } ll a[2*M]; int main() { ll n,m,x,y,rt = 0; scanf("%lld",&n); for(ll i = 1;i <= n;i ++){ scanf("%lld",&a[i]); } sort(a+1,a+1+n); for(ll i = 2;i <= n;i ++){ ll num = a[i] - a[i-1]; update(num,num,1,1e18,rt); } scanf("%lld",&m); for(ll i = 1;i <= m;i ++){ scanf("%lld%lld",&x,&y); ll num = y-x+1; ll ans = num; ans += query(1,num,1,1e18,rt); //cout<<ans<<" "; ans += ask(num+1,1e18,1,1e18,rt)*num; printf("%lld\n",ans); } }

Codeforces Global Round 2 D. Frets On Fire (動態開點線段樹,沙雕寫法)