Codeforces 题目传送门 & 洛谷题目传送门

一道难度 *3100 的 DS,而且被我自己搞出来了!

不过我终究还是技不如人,因为这是一个 \(n\log^2n\) + 大常数的辣鸡做法,几乎是卡着时空限制过去的……

首先注意到对于每个小马,在任意时刻它的法力值只有三种可能:

  • \(s_i+kr_i(k\in\mathbb{Z})\)
  • \(kr_i(k\in\mathbb{Z})\)
  • \(m_i\)

我们考虑对这三种情况一一分析,对于第一种情况这里的 \(k\) 只可能等于我们待查询的 \(t\),并且这种情况可能发生当且仅当 \(i\) 没有被清空过,并且 \(s_i+kr_i\le m_i\),第二个条件好办,我们如果设 \(a_i=\lfloor\dfrac{m_i-s_i}{r_i}\rfloor\)(如果 \(r_i=0\) 那么 \(a_i=\infty\)),那么 \(i\) 符合第二个条件当且仅当 \(a_i\ge t\),第一个条件虽然看起来棘手,但是我们可以维护一个 set 表示没有被清空过的集合,每次进行查询操作就将这个 set 中属于 \([l,r]\) 的元素全部删除,不难发现每个数最多被删除一次,因此复杂度是 \(n\log n\) 的。接下来问题就转化为如何维护这个值,显然它可以转化为 \(\sum\limits_{i=l}^r[a_i\ge t]s_i+t\sum\limits_{i=l}^r[a_i\ge t]r_i\),两部分结构类似,因此维护方法也类似,注意到这里涉及两维,\(i\in[l,r]\) 和 \(a_i\ge t\),那么该操作相当于查询矩形 \((l,a_i),(r,\infty)\) 中权值的和,这个离散化+建立二维线段树就可以搞定了,具体来说先将所有 \((i,a_i)\) 看作一个点并更新其在二维线段树上的权值,每次我们将一个数从 set 中删除就将对应的 \((i,a_i)\) 的贡献撤销掉,正确性显然。

搞清楚这个情况后,我们也可以顺带着把 \(i\) 没有被清空过的贡献都搞清楚,若 \(i\) 没有被清空过,可以分两种情况,\(a_i\ge t\) 那么贡献为 \(s_i+tr_i\),这个刚刚已经探究过了,\(a_i<t\) 那么贡献为 \(m_i\),不难发现这个也可以写成矩形和的形式,同样二维线段树维护即可,这里就不再赘述了。

\(i\) 没有被清空过的情况搞清楚了,接下来考虑 \(i\) 被清空过的情况,显然对于一个被清空过的 \(i\) 它都有一个上次被清空的时间 \(T_i\),在这 \(t-T_i\) 分钟内它的法力值最多可以上涨 \(r_i(t-T_i)\),那么它的贡献就是 \(\min(m_i,r_i(t-T_i))\),还是按照之前的套路,记 \(b_i=\lfloor\dfrac{m_i}{r_i}\rfloor\),还是分两种情况,若 \(b_i\ge t-T_i\),那么贡献为 \(r_i(t-T_i)\),否则贡献为 \(m_i\),这样还是不好做,因为这里的 \(T_i\) 都是互不相同的,无法直接维护。不过不难发现一个性质,那就是任意时刻 \(T_i\) 都是成段分布的,也就是说相同的 \(T_i\) 都是一段一段的,我们记三元组 \((l,r,t)\) 表示 \(\forall i\in[l,r],T_i=t\),我们考虑开一个 set 维护所有三元组并对每个三元组计算贡献——这个就可以按照上面的套路二维线段树了,相信如果理解了前面的部分那这边应该的相当容易的。我们还可以发现所有计算过贡献的三元组 \((l',r',t')\) 必定满足 \(l\le l'\le r'\le r\),这样的三元组在查询过后都会从 set 中删除,标准的 ODT 模型,按照 P4690 [Ynoi2016] 镜中的昆虫 的套路 维护即可。

时间复杂度 \(n\log^2n\),由于要维护五个二维线段树,常数巨大,但还好卡过去了(((

最后说一句,wtm 不是 sb,又拿未去重的数组离散化,话说恰好一年前的今天也犯过这个错误来着的?

const int MAXN=1e5;
const int MAXP=MAXN*20;
const int INF=0x3f3f3f3f;
int n,s[MAXN+5],r[MAXN+5],mx[MAXN+5],lim1[MAXN+5],lim2[MAXN+5];
int key1[MAXN+5],key2[MAXN+5],uni1[MAXN+5],uni2[MAXN+5],num1=0,num2=0;
struct seg2d{
struct node{int ch[2];ll sum;} s[MAXP+5];
int rt[MAXN+5],ncnt;
seg2d(){ncnt=0;memset(rt,0,sizeof(rt));}
void add_in(int &k,int l,int r,int x,int v){
if(!k) k=++ncnt;s[k].sum+=v;
if(l==r) return;int mid=l+r>>1;
if(x<=mid) add_in(s[k].ch[0],l,mid,x,v);
else add_in(s[k].ch[1],mid+1,r,x,v);
}
ll query_in(int k,int l,int r,int ql,int qr){
if(ql>qr||!k) return 0;int mid=l+r>>1;
if(ql<=l&&r<=qr) return s[k].sum;
if(qr<=mid) return query_in(s[k].ch[0],l,mid,ql,qr);
else if(ql>mid) return query_in(s[k].ch[1],mid+1,r,ql,qr);
else return query_in(s[k].ch[0],l,mid,ql,mid)+query_in(s[k].ch[1],mid+1,r,mid+1,qr);
}
void add_out(int x,int p,int v){
for(int i=x;i<=n;i+=(i&(-i))) add_in(rt[i],1,max(num1,num2),p,v);
}
ll query_out(int x,int l,int r){
ll ret=0;
for(int i=x;i;i&=(i-1)) ret+=query_in(rt[i],1,max(num1,num2),l,r);
return ret;
}
ll query(int l1,int r1,int l2,int r2){return query_out(r1,l2,r2)-query_out(l1-1,l2,r2);}
} t_s,t_r,t_m,T_r,T_m;
set<int> fst;
struct event{
int l,r,t;
event(int _l=0,int _r=0,int _t=0):l(_l),r(_r),t(_t){}
bool operator <(const event &rhs) const{return l<rhs.l;}
};
set<event> st;
void split(int x){
if(st.empty()) return;
set<event>::iterator it=st.lower_bound(event(x+1,0,0));
if(it==st.begin()) return;
--it;event val=*it;if(val.r<=x) return;
st.erase(st.find(val));
st.insert(event(val.l,x,val.t));
st.insert(event(x+1,val.r,val.t));
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d%d",&s[i],&mx[i],&r[i]);
for(int i=1;i<=n;i++){
if(r[i]){
lim1[i]=mx[i]/r[i];
lim2[i]=(mx[i]-s[i])/r[i];
} else lim1[i]=lim2[i]=INF;
}
for(int i=1;i<=n;i++) key1[i]=lim1[i],key2[i]=lim2[i];
sort(key1+1,key1+n+1);sort(key2+1,key2+n+1);key1[0]=-INF;key2[0]=-INF;
for(int i=1;i<=n;i++) if(key1[i-1]!=key1[i]) uni1[++num1]=key1[i];
for(int i=1;i<=n;i++) if(key2[i-1]!=key2[i]) uni2[++num2]=key2[i];
for(int i=1;i<=n;i++){
lim1[i]=lower_bound(uni1+1,uni1+num1+1,lim1[i])-uni1;//remember to unique
lim2[i]=lower_bound(uni2+1,uni2+num2+1,lim2[i])-uni2;
// printf("%d %d\n",lim1[i],lim2[i]);
}
for(int i=1;i<=n;i++) fst.insert(i);
for(int i=1;i<=n;i++){
t_s.add_out(i,lim2[i],s[i]);
t_r.add_out(i,lim2[i],r[i]);
t_m.add_out(i,lim2[i],mx[i]);
} int qu;scanf("%d",&qu);
while(qu--){
int t,L,R;scanf("%d%d%d",&t,&L,&R);
int pos=lower_bound(uni2+1,uni2+num2+1,t)-uni2;
ll sums=t_s.query(L,R,pos,num2);
ll sumr=t_r.query(L,R,pos,num2);
ll summ=t_m.query(L,R,1,pos-1);
// printf("%d %lld %lld %lld\n",pos,sums,sumr,summ);
// printf("%lld\n",summ+sums+sumr*t);
ll sum=summ+sums+sumr*t;
if(L!=1) split(L-1);split(R);
while(1){
set<event>::iterator it=st.lower_bound(event(L,0,0));
if(it==st.end()||(it->l)>R) break;event val=*it;
int pp=lower_bound(uni1+1,uni1+num1+1,t-val.t)-uni1;
ll ssumr=T_r.query(val.l,val.r,pp,num1);
ll ssumm=T_m.query(val.l,val.r,1,pp-1);
// printf("%d %d %d %d\n",val.l,val.r,t-val.t,pp);
// printf("%lld %lld\n",ssumr,ssumm);
sum+=ssumm+ssumr*(t-val.t);st.erase(st.find(val));
} st.insert(event(L,R,t));
while(1){
set<int>::iterator it=fst.lower_bound(L);
if(it==fst.end()||(*it)>R) break;
int x=(*it);
t_s.add_out(x,lim2[x],-s[x]);
t_r.add_out(x,lim2[x],-r[x]);
t_m.add_out(x,lim2[x],-mx[x]);
T_r.add_out(x,lim1[x],r[x]);
T_m.add_out(x,lim1[x],mx[x]);
fst.erase(fst.find(x));
} printf("%lld\n",sum);
}
return 0;
}
/*
10
0 4 2
0 3 0
0 96 7
0 25 9
0 90 4
0 93 5
0 87 3
0 58 3
0 65 8
0 30 0
10
3 3 4
10 1 7
11 8 9
19 4 9
28 3 10
33 5 10
38 4 5
45 5 7
48 5 9
58 1 4
*/

Codeforces 453E - Little Pony and Lord Tirek(二维线段树+ODT)的更多相关文章

  1. codeforces 677D D. Vanya and Treasure(二维线段树)

    题目链接: D. Vanya and Treasure time limit per test 1.5 seconds memory limit per test 256 megabytes inpu ...

  2. CodeForces 242E - XOR on Segment 二维线段树?

    今天练习赛的题....又是线段树的变换..拿到题我就敲了个点更新区间查询的..果断超时...然后想到了可以将每个数与合表示成不进位的二进制数..这样就可以区间进行更新了..比赛的时候写搓了..刚重写了 ...

  3. CodeForces 242E二维线段树

                                                                                           E. XOR on Seg ...

  4. 【Codeforces Round #433 (Div. 1) C】Boredom(二维线段树)

    [链接]我是链接 [题意] 接上一篇文章 [题解] 接(点我进入)上一篇文章. 这里讲一种用类似二维线段树的方法求矩形区域内点的个数的方法. 我们可以把n个正方形用n棵线段树来维护. 第i棵线段树维护 ...

  5. POJ2029 二维线段树

    Get Many Persimmon Trees POJ - 2029 Seiji Hayashi had been a professor of the Nisshinkan Samurai Sch ...

  6. UVA 11297 线段树套线段树(二维线段树)

    题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要  不同的处理方式,非叶子形成的 ...

  7. POJ2155 Matrix二维线段树经典题

    题目链接 二维树状数组 #include<iostream> #include<math.h> #include<algorithm> #include<st ...

  8. HDU 1823 Luck and Love(二维线段树)

    之前只知道这个东西的大概概念,没具体去写,最近呵呵,今补上. 二维线段树 -- 点更段查 #include <cstdio> #include <cstring> #inclu ...

  9. poj 2155:Matrix(二维线段树,矩阵取反,好题)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17880   Accepted: 6709 Descripti ...

随机推荐

  1. win10安装git fatal: open /dev/null or dup failed: No such file or directory错误解决方法

    原因看大家意思应该是 非即插即用驱动文件null.sys问题. 网上有很多方案.最后试了一个可行的. 替换  windows/system32/drivers/null.sys为网盘中的文件即可. 链 ...

  2. “妈妈再也不用担心我忘交作业了!”——记2020BUAA软工团队项目选择

    写在前面 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 团队项目选择 项目简介 项目名称:北航学生资源整合和作业提醒平台 项目内容: 设计实现一 ...

  3. [Beta]the Agiles Scrum Meeting 2

    会议时间:2020.5.11 20:00 1.每个人的工作 今天已完成的工作 成员 已完成的工作 yjy 修复bug将自动评测改为异步HTTP请求 tq 实现查看.删除测试点功能的后端将自动评测改为异 ...

  4. springBoot服务整合线程池ThreadPoolTaskExecutor与@Async详解使用

    ThreadPoolExecutor:=======这个是java自己实现的线程池执行类,基本上创建线程池都是通过这个类进行的创建.ThreadPoolTaskExecutor:========这个是 ...

  5. 使用logstash的grok插件解析springboot日志

    使用logstash的grok插件解析springboot日志 一.背景 二.解决思路 三.前置知识 四.实现步骤 1.准备测试数据 2.编写`grok`表达式 3.编写 logstash pipel ...

  6. kafka错误之 Topic xxx not present in metadata after 60000 ms

    Topic xxx not present in metadata after 60000 ms 一.背景 二.场景还原 1.jar包引入 2.jar代码 3.运行结果 三.问题解决 四.参考文档 一 ...

  7. PCB设计中新手和老手都适用的七个基本技巧和策略

    本文将讨论新手和老手都适用的七个基本(而且重要的)技巧和策略.只要在设计过程中对这些技巧多加注意,就能减少设计回炉次数.设计时间和总体诊断难点. 技巧一:注重研究制造方法和代工厂化学处理过程 在这个无 ...

  8. stop: Job failed while stopping start: Job is already running: networking eth0 not configured

    再给ubuntu系统重启网络服务的时候出现失败,"stop: Job failed while stopping start: Job is already running: network ...

  9. k8s入坑之路(7)kubernetes设计精髓List/Watch机制和Informer模块详解

    1.list-watch是什么 List-watch 是 K8S 统一的异步消息处理机制,保证了消息的实时性,可靠性,顺序性,性能等等,为声明式风格的API 奠定了良好的基础,它是优雅的通信方式,是 ...

  10. jenkins 生成HTML报表,邮件推送

    1.登录jenkins,系统管理=>插件管理 =>可选插件安装 安装成功: 2.打开任务,进入配置 3.添加构建后操作 4.配置页面 5.构建后report输出配置完成后点击立即构建,构建 ...