1. 程式人生 > 其它 >CF453E Little Pony and Lord Tirek

CF453E Little Pony and Lord Tirek

題面傳送門
題目有個肥腸神奇的地方就是詢問之後區間推平。
區間推平容易想到可以珂朵莉樹,然後如果暴力遍歷珂朵莉樹上每個節點,然後用可以接受的複雜度詢問,那麼就可以解決了。
發現珂朵莉樹上一個區間的推平時間是一樣的,也就是說到現在的時間是一樣的。
然後可以分成有沒有頂到上屆,離線樹狀陣列就好了。
時間複雜度\(O((n+m)\log n)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M (100+5)
#define K (20+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,Maxn=2,k,x,y,z,A[N],B[N];ll Ans[N],S[N];
namespace Tree{ll F[N],G[N];I void Ins(int x,int y,int z){while(x<=Maxn) F[x]+=y,G[x]+=z,x+=x&-x;}I ll Q1(int x){ll Ans=0;while(x) Ans+=F[x],x-=x&-x;return Ans;}I ll Q2(int x){ll Ans=0;while(x) Ans+=G[x],x-=x&-x;return Ans;}}
struct Line{int l,r,t,w;bool operator <(const Line &B)const{return l^B.l?l<B.l:r<B.r;};}P1;set<Line> F;set<Line>::it I1;
I void SP(int x){I1=F.lower_bound((Line){x+1,0,0,0});I1--;P1=*I1;F.erase(I1);F.insert((Line){P1.l,x,P1.t,P1.w});x^P1.r&&(F.insert((Line){x+1,P1.r,P1.t,P1.w}),0);}
struct Ques{int x,id,Fl;};vector<Ques> Q[N];
int main(){
//	freopen("1.in","r",stdin);
	int i;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d%d%d",&x,&A[i],&B[i]),S[i]=S[i-1]+B[i],F.insert((Line){i,i,0,x}),B[i]&&(Maxn=max(Maxn,A[i]/B[i]+2),0);
	scanf("%d",&m);for(i=1;i<=m;i++){
		scanf("%d%d%d",&z,&x,&y);x^1&&(SP(x-1),0);SP(y);while(1){
			I1=F.lower_bound((Line){x,0,0,0});if(I1==F.end()) break;P1=*I1;if(P1.l>y) break;if(P1.w) Ans[i]+=min(1ll*(z-P1.t)*B[P1.l]+P1.w,A[P1.l]);
			else Ans[i]+=1ll*(S[P1.r]-S[P1.l-1])*(z-P1.t),Q[P1.r].PB((Ques){z-P1.t,i,1}),Q[P1.l-1].PB((Ques){z-P1.t,i,-1});F.erase(I1);
		}F.insert((Line){x,y,z,0});
	}for(i=1;i<=n;i++) {B[i]&&(Tree::Ins((A[i]+B[i]-1)/B[i]+1,A[i],B[i]),0);for(Ques d:Q[i]) Ans[d.id]+=d.Fl*Tree::Q1(min(d.x+1,Maxn))-d.x*Tree::Q2(min(d.x+1,Maxn))*d.Fl;}for(i=1;i<=m;i++) printf("%lld\n",Ans[i]);
}