P3710 方方方的数据结构(kd-tree)

解析

写吐了…

一开始觉得线段树分治直接做就行简直是个伞兵题,写完挂掉才想起来线段树分治会打乱操作顺序导致全假…
重构吧!
炸裂之下去贺题解,std做法 O ( m m log ⁡ m ) O(m\sqrt m\log m) O(mm logm) 令人谔谔,但kd-tree做法确实挺伞兵的,懊恼为啥没有想到。
写完交后发现MLE成20,用现成的datamaker跑个1000的数据发现就开了7e5个点???
…原来矩形修改开虚点复杂度会假掉啊,我直接一种植物。
重构吧!
…终于过了。
思维还是要灵活,这个转二维数点其实挺直观的。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read() {
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
  while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}

const int N=2e5+100;
const double inf=1e18;
const int mod=998244353;

inline ll ksm(ll x,ll k){
  ll res=1;
  while(k){
    if(k&1) res=res*x%mod;
    x=x*x%mod;
    k>>=1;
  }
  return res;
}

int n,m;

struct tag{
  ll mul,add;  
}I=(tag){1,0};
tag operator + (const tag x,const tag y){
  return (tag){x.mul*y.mul%mod,(x.add*y.mul+y.add)%mod};
}

struct pt{
  int x[2];
}q[N];
int num;
int F;
bool operator < (const pt &x,const pt &y){return x.x[F]<y.x[F];}
struct tree{
  int ch[2];
  int l[2],r[2];
  pt o;
  tag ans,laz;
}tr[N];
inline void pushup(int k){
  tr[k].l[0]=tr[k].r[0]=tr[k].o.x[0];
  tr[k].l[1]=tr[k].r[1]=tr[k].o.x[1];
  for(int o=0;o<=1;o++){
    int son=tr[k].ch[o];
    if(!son) continue;
    for(int d=0;d<=1;d++){
      tr[k].l[d]=min(tr[k].l[d],tr[son].l[d]);
      tr[k].r[d]=max(tr[k].r[d],tr[son].r[d]);
    }
  }
  return;
}
inline void Add(int k,const tag &o){
  if(!k) return;
  tr[k].ans=tr[k].ans+o;
  tr[k].laz=tr[k].laz+o;
}
inline void pushdown(int k){
  Add(tr[k].ch[0],tr[k].laz);
  Add(tr[k].ch[1],tr[k].laz);
  tr[k].laz=I;
}
int tot;
int build(int l,int r,int d){
  if(l>r) return 0;
  int now=++tot,mid=(l+r)>>1;
  F=d;  
  nth_element(q+l,q+mid,q+r+1);
  tr[now].o=q[mid];
  tr[now].ans=tr[now].laz=I;
  tr[now].ch[0]=build(l,mid-1,d^1);
  tr[now].ch[1]=build(mid+1,r,d^1);
  pushup(now);
  return now;
}
struct node{
  int l[2],r[2];
};
void upd(int k,const node &o,const tag &w){
  if(!k) return;
  if(o.l[0]>tr[k].r[0]||o.r[0]<tr[k].l[0]||o.l[1]>tr[k].r[1]||o.r[1]<tr[k].l[1]) return;
  if(o.l[0]<=tr[k].l[0]&&tr[k].r[0]<=o.r[0]&&o.l[1]<=tr[k].l[1]&&tr[k].r[1]<=o.r[1]){
    Add(k,w);
    return;
  }
  pushdown(k);
  if(o.l[0]<=tr[k].o.x[0]&&tr[k].o.x[0]<=o.r[0]&&o.l[1]<=tr[k].o.x[1]&&tr[k].o.x[1]<=o.r[1])
    tr[k].ans=tr[k].ans+w;
  upd(tr[k].ch[0],o,w);
  upd(tr[k].ch[1],o,w);
}
ll ans[N];
void getans(int k){
  if(!k) return;
  ans[tr[k].o.x[1]]=tr[k].ans.add;
  pushdown(k);
  getans(tr[k].ch[0]);
  getans(tr[k].ch[1]);
  return;
}

int op[N],l[N],r[N],val[N],pos[N],tim[N];
signed main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  n=read();m=read();  
  for(int i=1;i<=m;i++){
    op[i]=read();
    if(op[i]<=2){
      l[i]=read();r[i]=read();
      val[i]=read();
      tim[i]=m;
    }
    else if(op[i]==3){      
      pos[i]=read();
      q[++num]=(pt){pos[i],i};
    }
    else tim[read()]=i;   
  }
  int rt=build(1,num,0);
  for(int i=1;i<=m;i++){
    if(op[i]<=2){
      tag w=I;
      if(op[i]==1) w.add=val[i];
      else w.mul=val[i];
      node o;
      o.l[0]=l[i];o.r[0]=r[i];
      o.l[1]=i;o.r[1]=tim[i];
      //printf("upd: (%d %d) (%d %d) mul=%d add=%d\n",o.l[0],o.r[0],o.l[1],o.r[1],mul,add);
      upd(rt,o,w);
    }
  }
  getans(rt);
  for(int i=1;i<=m;i++){
    if(op[i]==3) printf("%lld\n",ans[i]);
  }
  debug("tot=%d\n",tot);
  return 0;
}
/*
 */
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值