ATcoder 两题
Atcoder 两题
AT_abc365_f
题目描述(来自谷歌翻译)
平面上有无数个单元格。对于每对整数
每个单元格要么是空单元格,要么是壁单元格。
给定两个长度为
所有单元格
当 Takahashi 位于空单元格
- 如果单元格
为空单元格,则移至单元格 。 - 如果单元格
为空单元格,则移至单元格 。 - 如果单元格
为空单元格,则移至单元格 。 - 如果单元格
为空单元格,则移至单元格 。
保证他可以通过重复他的操作在任意两个空单元格之间移动。
按照以下格式回答
对于第
思路点拨
为了方便讨论,默认每一次存在有
考虑单次询问最简单的怎么做,就是暴力
但是稍微有经验的同学会知道
,那么 的位置不会发生变化。 ,那么 会变成 。 , 那么 会变成 。
那么我们就获得了一个
注意到一个关键的性质:当
定义倍增数组
考虑
每一次查询,我们只需要知道
总体时间复杂度
示范代码
#include<bits/stdc++.h>
#define int long long
#pragma GCC optimize(2)
using namespace std;
namespace fastIO{
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int buf[20],TOT;
inline void print(int x,char ch=' '){
if(x<0) putchar('-'),x=-x;
else if(x==0) buf[++TOT]=0;
for(int i=x;i;i/=10) buf[++TOT]=i%10;
do{putchar(buf[TOT]+'0');}while(--TOT);
putchar(ch);
}
}
using namespace fastIO;
const int MAXN=2e5+5;
int n,m,L[MAXN],R[MAXN];
struct node1{
int t[MAXN<<2];
void update(int i,int l,int r,int k,int w){
if(l==r){
t[i]=w;
return ;
}
int mid=(l+r)>>1;
if(k<=mid) update(i<<1,l,mid,k,w);
else update(i<<1|1,mid+1,r,k,w);
t[i]=min(t[i<<1],t[i<<1|1]);
}
int query(int i,int l,int r,int L,int R){
if(L<=l&&r<=R) return t[i];
int mid=(l+r)>>1;
if(R<=mid) return query(i<<1,l,mid,L,R);
if(mid<L) return query(i<<1|1,mid+1,r,L,R);
return min(query(i<<1,l,mid,L,mid),query(i<<1|1,mid+1,r,mid+1,R));
}
}tr,tl;
struct node2{
int t[MAXN<<2];
void update(int i,int l,int r,int k,int w){
if(l==r){
t[i]=w;
return ;
}
int mid=(l+r)>>1;
if(k<=mid) update(i<<1,l,mid,k,w);
else update(i<<1|1,mid+1,r,k,w);
t[i]=max(t[i<<1],t[i<<1|1]);
}
int query(int i,int l,int r,int L,int R){
if(L<=l&&r<=R) return t[i];
int mid=(l+r)>>1;
if(R<=mid) return query(i<<1,l,mid,L,R);
if(mid<L) return query(i<<1|1,mid+1,r,L,R);
return max(query(i<<1,l,mid,L,mid),query(i<<1|1,mid+1,r,mid+1,R));
}
}Tr,Tl;
int nxt_min(int p,int val,node1 &t){
int l=p,r=n+1;
while(l<r){
int mid=(l+r)>>1;
if(t.query(1,1,n+1,p,mid)<val)
r=mid;
else l=mid+1;
}
return l;
}
int nxt_max(int p,int val,node2 &t){
int l=p,r=n+1;
while(l<r){
int mid=(l+r)>>1;
if(t.query(1,1,n+1,p,mid)>val)
r=mid;
else l=mid+1;
}
return l;
}
struct node{
int a,b,val;
node(int x=0,int y=0,int z=0){
a=x,b=y,val=z;
}
}nxt[MAXN][20][2];
signed main(){
n=read();
for(int i=1;i<=n;i++)
L[i]=read(),R[i]=read();
for(int i=1;i<=n;i++){
tr.update(1,1,n+1,i,R[i]);
tl.update(1,1,n+1,i,L[i]);
Tr.update(1,1,n+1,i,R[i]);
Tl.update(1,1,n+1,i,L[i]);
}
tr.update(1,1,n+1,n+1,-1);
tl.update(1,1,n+1,n+1,-1);
Tr.update(1,1,n+1,n+1,1e9+5);
Tl.update(1,1,n+1,n+1,1e9+5);
//小写维护min,大写维护max
for(int i=1;i<=n;i++){
int p1,p2;
p1=nxt_max(i,L[i],Tl);
p2=nxt_min(i,L[i],tr);
if(p1<p2)
nxt[i][0][0]=node(p1,0,(p1-i)+abs(L[p1]-L[i]));
else
nxt[i][0][0]=node(p2,1,(p2-i)+abs(L[i]-R[p2]));
}
for(int i=1;i<=n;i++){
int p1,p2;
p1=nxt_max(i,R[i],Tl);
p2=nxt_min(i,R[i],tr);
if(p1<p2)
nxt[i][0][1]=node(p1,0,(p1-i)+abs(L[p1]-R[i]));
else
nxt[i][0][1]=node(p2,1,(p2-i)+abs(R[i]-R[p2]));
}
nxt[n+1][0][0]=nxt[n+1][0][1]=node(n+1,0,0);
for(int j=1;j<20;j++){
for(int i=1;i<=n+1;i++){
for(int k=0;k<2;k++){
node s1=nxt[i][j-1][k],s2=nxt[s1.a][j-1][s1.b];
nxt[i][j][k]=node(s2.a,s2.b,s1.val+s2.val);
}
}
}
m=read();
while(m--){
int x1=read(),y1=read(),x2=read(),y2=read();
if(x1>x2){
swap(x1,x2);
swap(y1,y2);
}
int p1=nxt_min(x1,y1,tr),p2=nxt_max(x1,y1,Tl);
if(min(p1,p2)>x2) print(x2-x1+abs(y1-y2),'\n');
else{
int ans=0,x,y;
if(p1<p2){
ans+=abs(x1-p1)+abs(y1-R[p1]);
x=p1,y=1;
}
else{
ans+=abs(x1-p2)+abs(y1-L[p2]);
x=p2,y=0;
}
for(int i=19;i>=0;i--){
if(nxt[x][i][y].a<=x2){
node s=nxt[x][i][y];
x=s.a,y=s.b,ans+=s.val;
}
}
y=y?R[x]:L[x];
ans+=abs(x2-x)+abs(y2-y);
print(ans,'\n');
}
}
return 0;
}
AT_abc365_f
题目描述(来自谷歌翻译)
办公室保存进出记录,自记录开始以来,已有
第
众所周知,记录开始时所有人都在办公室外面,现在他们都在外面。
按照以下格式回答
对于第
思路点拨
听说有根号分治的做法会比较简单?这是一份分块做法,还有点复杂。
认为
发现题目的询问比较复杂的样子,不具备什么合并的性质,不好扫描线什么的,所以可以往分块上想,按照时间点离散化后分块,设块长为
对于每一个人,它在办公室的时间是一个个区间,并且全部人的区间数量是
现在的问题是
也是零散块。 是完整块。
先解决
现在问题就在于
当
示范代码
#include<bits/stdc++.h>
//#define int long long
using namespace std;
namespace fastIO{
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int buf[20],TOT;
inline void print(int x,char ch=' '){
if(x<0) putchar('-'),x=-x;
else if(x==0) buf[++TOT]=0;
for(int i=x;i;i/=10) buf[++TOT]=i%10;
do{putchar(buf[TOT]+'0');}while(--TOT);
putchar(ch);
}
}
using namespace fastIO;
const int MAXN=2e5+5;
int n,m,q,B;
int pre[MAXN],pos[MAXN];
vector<pair<int,int>> e[MAXN],qry[MAXN];
int s[500][MAXN];
struct node{
int l,r,num;
};
vector<node> ins[500];
int bl[MAXN],br[MAXN];
void init(){
int l=1,r=B,id=1;
while(1){
bl[id]=l,br[id]=r;
if(r==m) break;
l=r,r=min(m,r+B);
id++;
}
}
void insert(int ql,int qr,int p){
int l=1,r=B,id=1;
while(1){
if(ql<=l&&r<=qr)
s[id][p]+=pos[r]-pos[l];
else{
int L=max(ql,l),R=min(qr,r);
if(L<R){
ins[id].push_back((node){L,R,p});
s[id][p]+=pos[R]-pos[L];
}
}
if(r==m) break;
l=r,r=min(m,r+B);
id++;
}
}
vector<int> f;
int ans[MAXN],sum[MAXN],g[500];
bool vis[MAXN];
int stk[MAXN],top;
void query(int ql,int qr,int p){
int l=1,r=B,id=1;
while(1){
if(ql<=l&&r<=qr) f.push_back(id);
else{
int L=max(ql,l),R=min(qr,r);
if(L<R){
g[id]+=pos[R]-pos[L];
for(auto I:ins[id]){
int x=max(L,I.l),y=min(R,I.r);
if(x<=y) sum[I.num]+=pos[y]-pos[x];
if(!vis[I.num]) vis[I.num]=1,stk[++top]=I.num;
}
}
}
if(r==m) break;
l=r,r=min(m,r+B);
id++;
}
}
int find(int p){
int sum=0;
for(int i:f) sum+=s[i][p];
int l=1,r=B,id=1;
while(1){
if(pos[r]-pos[l]==s[id][p]) sum+=g[id];
if(r==m) break;
l=r,r=min(m,r+B);
id++;
}
return sum;
}
signed main(){
n=read(),m=read();
B=sqrt(m);
init();
for(int i=1;i<=m;i++){
pos[i]=read();
int id=read();
if(!pre[id]) pre[id]=i;
else e[id].push_back(make_pair(pre[id],i)),pre[id]=0;
}
for(int i=1;i<=n;i++)
for(auto j:e[i]) insert(j.first,j.second,i);
q=read();
for(int i=1;i<=q;i++){
int x=read(),y=read();
qry[x].push_back(make_pair(y,i));
}
for(int i=1;i<=n;i++){
f.clear();
for(auto j:e[i]) query(j.first,j.second,i);
for(auto j:qry[i])
ans[j.second]=sum[j.first]+find(j.first);
while(top){
sum[stk[top]]=vis[stk[top]]=0;
top--;
}
for(int j=1;j<=B+5;j++) g[j]=0;
}
for(int i=1;i<=q;i++) print(ans[i],'\n');
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)