[做题记录]珂朵莉树/势能线段树
势能线段树还没学。
所以更新的都是一些珂朵莉的题目。
长期更新。
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
考虑一次取值相当于区间打上一个时间戳。
然后考虑一次查询时,等同查询
注意其有初值,所以需要在维护两颗主席树,然后在查询时在珂朵莉的区间打一个是否操作过一次的标记。
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;
}
}
本文作者:fhq_treap
本文链接:https://www.cnblogs.com/dixiao/p/15664669.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 依赖注入中的 Captive Dependency
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· 一个适用于 .NET 的开源整洁架构项目模板
· API 风格选对了,文档写好了,项目就成功了一半!
· 【开源】C#上位机必备高效数据转换助手
· .NET 9.0 使用 Vulkan API 编写跨平台图形应用
· MyBatis中的 10 个宝藏技巧!