zoukankan      html  css  js  c++  java
  • [做题记录]珂朵莉树/势能线段树

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

    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;
    	}
    } 
    
  • 相关阅读:
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十一)
    install ubuntu on Android mobile phone
    Mac OS, Mac OSX 与Darwin
    About darwin OS
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十)
    Linux下编译安装qemu和libvirt
    libvirt(virsh命令总结)
    深入浅出 kvm qemu libvirt
    自然语言交流系统 phxnet团队 创新实训 项目博客 (九)
    自然语言交流系统 phxnet团队 创新实训 项目博客 (八)
  • 原文地址:https://www.cnblogs.com/dixiao/p/15664669.html
Copyright © 2011-2022 走看看