[做题记录]珂朵莉树/势能线段树

势能线段树还没学。
所以更新的都是一些珂朵莉的题目。
长期更新。

CF444C DZY Loves Colors

考虑这种区间颜色推平,就可以使用珂朵莉树。

因为其颜色推平时,变成一个颜色的代价相同则我们直接在线段树上把这段加上去就行了。

CF444C DZY Loves Colors
#include<bits/stdc++.h>
#define N 100005
#define ll long long

struct P{
	int l,r;
	mutable int v;
	P(int L,int R = -1,int V = 0):l(L),r(R),v(V){}
};

bool operator < (P a,P b){
	return a.l < b.l;
}

ll T[N << 2];
ll tag[N << 2];

#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define mid ((l + r) >> 1)

inline void up(int u){T[u] = T[ls(u)] + T[rs(u)];}

inline void down(int u,int l,int r){
	if(tag[u]){
		tag[ls(u)] += tag[u];
		tag[rs(u)] += tag[u];
		T[ls(u)] += (tag[u] * 1ll * (mid - l + 1));
		T[rs(u)] += (tag[u] * 1ll * (r - mid));
		tag[u] = 0;
	}
}

inline void add(int u,int l,int r,int tl,int tr,int p){
	if(tl <= l && r <= tr){
		tag[u] += p;
		T[u] += p * 1ll * (r - l + 1);
		return ;
	}
	down(u,l,r);
	if(tl <= mid)
	add(ls(u),l,mid,tl,tr,p);
	if(tr > mid)
	add(rs(u),mid + 1,r,tl,tr,p);
	up(u);
} 

inline ll find(int u,int l,int r,int tl,int tr){
	if(tl <= l && r <= tr)
	return T[u];
	down(u,l,r);
	ll ans = 0;
	if(tl <= mid)
	ans = ans + find(ls(u),l,mid,tl,tr);
	if(tr > mid)
	ans = ans + find(rs(u),mid + 1,r,tl,tr);
	return ans;
}

std::set<P>A;

#define IT std::set<P>::iterator

IT split(int x){
	IT it = A.lower_bound(P(x));
	if(it != A.end() && it -> l == x)return it;
	-- it;
	int l = it -> l,r = it -> r,v = it -> v; 
	A.erase(it);
	A.insert(P(l,x - 1,v));
	return A.insert(P(x,r,v)).first;
}

int n,m;

#define root 1,1,n

inline void cover(int l,int r,int v){
	IT itr = split(r + 1),itl = split(l);
	IT it = itl;
	while(it != itr){
		int L = it -> l,R = it -> r,V = it -> v;
		add(root,L,R,abs(V - v));
		++it;
	}
	A.erase(itl,itr);
	A.insert(P(l,r,v));
} 

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;++i){
		A.insert(P(i,i,i));
	}
	while(m -- ){
		int opt ;
		scanf("%d",&opt);
		if(opt == 1){
			int l,r,x;
			scanf("%d%d%d",&l,&r,&x);
			cover(l,r,x);
		}else{
			int l,r;
			scanf("%d%d",&l,&r);
			std::cout<<find(root,l,r)<<std::endl;
		}
	}
}

CF453E Little Pony and Lord Tirek

考虑一次取值相当于区间打上一个时间戳。

然后考虑一次查询时,等同查询\([l,r]\)里扩展上界小于\(now - las\)\(\sum m\)以及扩展上界大于\(now - las\)\(\sum p\),可以主席树操作完成。

注意其有初值,所以需要在维护两颗主席树,然后在查询时在珂朵莉的区间打一个是否操作过一次的标记。

\(O(nlogn)\)

CF453E Little Pony and Lord Tirek
#include<bits/stdc++.h>
#define N 100005
#define ll long long 

int n;
int s[N],m[N],r[N];
ll pre[N];

using std::set;

struct P{
	int l,r;
	mutable int v;//时间戳
	bool opt;//是否操作过
	P(int L,int R = -1,int V = 0,int op = 0):l(L),r(R),v(V),opt(op){} 
}; 

bool operator < (P a,P b){
	return a.l < b.l;
}

ll M[(N * 20) << 1];//0:never 1:done sum m

ll K[(N * 20) << 1];//0:never 1:done sum k

int head[N][2];//头结点

int ch[(N * 20) << 1][2];//儿子

#define ls(x) ch[x][0]
#define rs(x) ch[x][1] 
#define mid ((l + r) >> 1) 

int cnt;

inline void up(int u){M[u] = M[ls(u)] + M[rs(u)];K[u] = K[ls(u)] + K[rs(u)];}

inline void add(int lasu,int &u,int l,int r,int p,int mi,int ki){
	if(!u)
	u = ++ cnt;
//	std::cout<<lasu<<" "<<u<<" "<<l<<" "<<r<<" "<<p<<" "<<mi<<" "<<ki<<std::endl; 	
	if(l == r){
		M[u] = M[lasu] + mi,K[u] = K[lasu] + ki;
		return ;
	}
	if(p <= mid)
	rs(u) = rs(lasu),add(ls(lasu),ls(u),l,mid,p,mi,ki);
	else
	ls(u) = ls(lasu),add(rs(lasu),rs(u),mid + 1,r,p,mi,ki);	
	up(u);
} 

inline ll lq(int u,int l,int r,int k){
	if(!u)return 0;
	if(r <= k)
	return M[u];
	if(k <= mid)
	return lq(ls(u),l,mid,k);
	else
	return M[ls(u)] + lq(rs(u),mid + 1,r,k);
}

inline ll rq(int u,int l,int r,int k){
	if(!u)return 0;
	if(l >= k)
	return K[u];
	if(k <= mid)
	return rq(ls(u),l,mid,k) + K[rs(u)];
	else
	return rq(rs(u),mid + 1,r,k);
}

inline ll leq(int l,int r,int time,int op){
	time = std::min(time,(int)1e5 + 1);
	return lq(head[r][op],0,N,time) - lq(head[l - 1][op],0,N,time);
}

inline ll req(int l,int r,int time,int op){
	time = std::min(time,(int)1e5 + 1);
//	std::cout<<"req "<<l<<" "<<r<<" "<<time<<" "<<op<<" "<<rq(head[r][op],0,N,time)<<std::endl; 
	return rq(head[r][op],0,N,time) - rq(head[l - 1][op],0,N,time);
}

//主席树 

set<P>A;

#define IT set<P>::iterator 

inline IT split(int x){
	IT it = A.lower_bound(x);
	if(it != A.end() && it -> l == x)return it;
	-- it;
	int l = it -> l,r = it -> r,v = it -> v,op = it -> opt;
	A.erase(it);
	A.insert(P(l,x - 1,v,op));
	return A.insert(P(x,r,v,op)).first; 
}

inline ll find(int l,int r,int t){
	IT itr = split(r + 1),itl = split(l);
	IT it = itl;
	ll ans = 0;
	while(it != itr){ 
		int time = t - it -> v;
		if(!(it -> opt))
		ans = ans + pre[it -> r] - pre[(it -> l) - 1];
		ans = ans + leq(it -> l,it -> r,time - 1,it -> opt) + time * req(it -> l,it -> r,time,it -> opt); 
//		std::cout<<it -> l<<" "<<it -> r<<" "<<it -> v<<std::endl;
//		std::cout<<ans<<" "<<time<<std::endl;		
		++it;
	}
	A.erase(itl,itr);
	A.insert(P(l,r,t,1));
	return ans;
}

template<typename T> void read(T &x){
	x=0;int f=1;
	char ch=getchar();
	while(!isdigit(ch)) f=(ch=='-'?-1:f),ch=getchar();
	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
	x=x*f;
}

//珂朵莉 

signed main(){
	scanf("%lld",&n);
	for(int i = 1;i <= n;++i){
		read(s[i]);
		read(m[i]);
		read(r[i]);
		pre[i] = pre[i - 1] + s[i];
//		puts("!");
//		std::cout<<i<<std::endl;		
		//del case 1 : never
		int pi,mi;
		mi = m[i] - s[i];
		if(r[i] == 0)
		pi = 100003;
		else
		pi = mi / r[i];
//		puts("!0");
//		std::cout<<pi<<" "<<mi<<" "<<r[i]<<std::endl;		
		add(head[i - 1][0],head[i][0],0,N,pi,mi,r[i]);
		//del case 2 : done		
		mi = m[i];
		if(r[i] == 0)
		pi = 100003;
		else
		pi = mi / r[i];
//		puts("!1");
//		std::cout<<pi<<" "<<mi<<" "<<r[i]<<std::endl;		
		add(head[i - 1][1],head[i][1],0,N,pi,mi,r[i]);		
	}
	A.insert(P(1,n,0,0));
	int q;
	scanf("%lld",&q);
	while(q -- ){
		int t,l,r;
		read(t);
		read(l);
		read(r);
		std::cout<<find(l,r,t)<<std::endl;
	}
} 
原文地址:https://www.cnblogs.com/dixiao/p/15664669.html