51Nod 算法马拉松12 Rikka with sequences

当时做比赛的时候听说过这类用KD_Tree维护的数据结构题

然后知道是KD_Tree,然而并不知道怎么写QAQ

比赛完了之后%了一发代码

其基本思路是这样的:

1、首先我们把询问[L,R]看成二维平面上的点,那么对于任意修改[p,p]

当且仅当p>=L&&p<=R时会对答案有影响

对应到二维平面就是KD_Tree维护矩形区域和的经典操作啦

2、那么我们考虑对历史最小值的询问

先把修改转换为增量修改

我们可以在KD_Tree上维护两个标记

第一个是当前的ADD

第二个是历史所有的Minadd

这样在更改一下push_down函数就可以完成了

QAQ 高仿的代码,真是羞耻 QAQ

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;

typedef long long LL;
const int maxn=100010;
const int oo=0x7fffffff;
int n,m,D,cnt,rt;
int A[maxn],type[maxn],L[maxn],R[maxn];
LL Bit[maxn],ans[maxn];

void add(int x,int v){for(int i=x;i<=n;i+=(i&(-i)))Bit[i]+=v;}
LL ask(int x){
    LL sum=0;
    for(int i=x;i>=1;i-=(i&(-i)))sum+=Bit[i];
    return sum;
}
int tot=0;
struct Node{
    int d[2],mn[2],mx[2];
    int L,R,id;
    LL sum,add,ans,Minadd;
    bool operator <(const Node &A){return d[D]<A.d[D];}
}t[maxn],tmp[maxn];
void up(int o){
    for(int i=0;i<2;++i){
        t[o].mn[i]=min(t[o].d[i],min(t[t[o].L].mn[i],t[t[o].R].mn[i]));
        t[o].mx[i]=max(t[o].d[i],max(t[t[o].L].mx[i],t[t[o].R].mx[i]));
    }return;
}
void push_1(int o,LL v){
    if(!o)return;
    t[o].ans=min(t[o].ans,t[o].sum+v);
    t[o].Minadd=min(t[o].Minadd,t[o].add+v);
}
void push_2(int o,LL v){
    if(!o)return;
    t[o].sum+=v;t[o].add+=v;
    t[o].ans=min(t[o].ans,t[o].sum);
    t[o].Minadd=min(t[o].Minadd,t[o].add);
}
void push_down(int o){
    if(t[o].Minadd){
        push_1(t[o].L,t[o].Minadd);
        push_1(t[o].R,t[o].Minadd);
        t[o].Minadd=0;
    }
    if(t[o].add){
        push_2(t[o].L,t[o].add);
        push_2(t[o].R,t[o].add);
        t[o].add=0;
    }
}
void modify(int o,int p,int val){
    if(!o)return;
    push_down(o);
    if(t[o].mx[0]<=p&&t[o].mn[1]>=p){push_2(o,1LL*val);return;}
    if(t[o].d[0]<=p&&t[o].d[1]>=p)t[o].sum+=val,t[o].ans=min(t[o].ans,t[o].sum);
    if(t[t[o].L].mn[0]<=p&&t[t[o].L].mx[1]>=p)modify(t[o].L,p,val);
    if(t[t[o].R].mn[0]<=p&&t[t[o].R].mx[1]>=p)modify(t[o].R,p,val);
}
void insert(int &o,int x,int y,int id,int c){
    if(!o){
        o=++tot;t[o].d[0]=x;t[o].d[1]=y;
        t[o].id=id;t[o].sum=t[o].ans=ask(y)-ask(x-1);
        up(o);
        return;
    }
    push_down(o);
    if(c==0){
        if(x<=t[o].d[0])insert(t[o].L,x,y,id,c^1);
        else insert(t[o].R,x,y,id,c^1);
    }else{
        if(y<=t[o].d[1])insert(t[o].L,x,y,id,c^1);
        else insert(t[o].R,x,y,id,c^1);
    }up(o);
}
void DFS(int o){
    if(!o)return;
    push_down(o);
    DFS(t[o].L);
    tmp[++cnt]=t[o];
    ans[t[o].id]=t[o].ans;
    DFS(t[o].R);
}
void build(int &o,int L,int R,int c){
    o=0;if(L>R)return;
    int mid=(L+R)>>1;D=c;o=mid;
    nth_element(tmp+L,tmp+mid,tmp+R+1);
    t[o]=tmp[mid];
    build(t[o].L,L,mid-1,c^1);
    build(t[o].R,mid+1,R,c^1);
    up(o);
}
int main(){
    rt=0;
    t[0].mn[0]=t[0].mn[1]=oo;
    t[0].mx[0]=t[0].mx[1]=-oo;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&A[i]),add(i,A[i]);
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&type[i],&L[i],&R[i]);
        if(type[i]==1){
            add(L[i],R[i]-A[L[i]]);
            R[i]=R[i]-A[L[i]];
            A[L[i]]+=R[i];
        }
    }
    int blo=2000;
    for(int i=m;i>=1;--i){
        if(type[i]==1)modify(rt,L[i],-R[i]),add(L[i],-R[i]);
        else insert(rt,L[i],R[i],i,0);
        if(i%blo==0){
            cnt=0;DFS(rt);rt=0;
            build(rt,1,cnt,0);
        }
    }
    cnt=0;DFS(rt);
    for(int i=1;i<=m;++i){
        if(type[i]==2)printf("%lld\n",ans[i]);
    }return 0;

}

Rikka with sequences

时间: 2024-12-23 10:39:21

51Nod 算法马拉松12 Rikka with sequences的相关文章

51Nod 算法马拉松21(迎新年)

这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =). 讲讲比赛经过吧. 8:00准时发题,拿到之后第一时间开始读. A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过读后面的题. B完全二叉树的方差,大概看了一遍,好神的样子,跳过. C多项式?好吧没学过FFT和NTT的我肯定不会,跳跳跳. D最大值,哎呦这函数什么破玩意儿,看不懂,跳跳跳. E B君的射击,卧槽毕克大人您出题就算了出这么一道码农题是要闹那样,跳跳跳. F那些年,我们一起讲的故事,卧槽这特么简直就

随便玩玩系列之一:SPOJ-RNG+51nod 算法马拉松17F+51nod 1034 骨牌覆盖v3

先说说前面的SPOJ-RNG吧,题意就是给n个数,x1,x2,...,xn 每次可以生成[-x1,x1]范围的浮点数,把n次这种操作生成的数之和加起来,为s,求s在[A,B]内的概率 连续形的概率,想象为一个n维长方体,有两个平面与这个几何图形相割,于是就变成了求面(体)积问题,一般要去重,n维区域系数:s^n/n!,至于区间问题,直接前缀之差搞定 然后就是悲催的算法马拉松17F题了...其实是道好题来的,只是出题人不知世界上还有这题,然后某大牛把思路理清后把答案直接搬了过来 经典的1*2骨牌覆

51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛

OwO 故事的起源大概是zcg前天发现51Nod晚上有场马拉松,然后他就很开心的过去打了 神奇的故事就开始了: 晚上的时候我当时貌似正在写线段树?然后看见zcg一脸激动告诉我第一题有九个点直接输出B就可以A.. 然后之后zcg以奇怪的二分方式发现了如何A掉第一题的第十个点(我记得貌似是什么第5000个数等于511? OwO 就这样没有任何思考含量全凭骗分黑科技过掉了第一题 OwO 然后zcg打开了第二题,发现第二题样例有点问题,然后就发了个帖子,直接去看第三题了 我去瞅了一眼,发现这不是gcd

51nod算法马拉松 contest7

A题 链接:http://www.51nod.com/contest/problem.html#!problemId=1417 推荐链接:http://blog.csdn.net/a837199685/article/details/45009337 设美女取得正面概率是p,反面就是(1-p),就是美女取一正一反和一反一正的概率相同,然后推出公式y=((a+b)/2+b)/(2*(a+b)); 1 #include<iostream> 2 #include<cstdio> 3 #i

51Nod 算法马拉松23 开黑记

惨啊--虽然开了半天黑,但是还是被dalao们踩了-- 第二次开黑,还是被卡在rank20了,我好菜啊--= = 写一写比赛经过吧-- 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是道数论题,看了E感觉有点意思,一看数据范围,咦怎么只有$50000$,再仔细看一看式子,手动分情况讨论之后得到一个结论-- 这题是水的线段树维护莫队啊= = 然后就开始码码码,由于一些脑残错误调了一会儿,然后就得到了这样的结果: 我坚信自己莫队的复杂度没错,然后就开始各种王逸松卡常,使用的卡常技巧包

51nod 算法马拉松4

http://www.51nod.com/contest/problemList.html#!contestId=9 D 装盒子 拓扑排序?

51NOD算法马拉松 最大值问题 离线预处理+set lower_bound

题目:http://www.51nod.com/contest/problem.html#!problemId=1349 题意:100000个数的序列,有100000次询问,每次问区间最大值大于等于k的区间有多少? 思路:一开始没看到"大于等于",想了很久也不会,原来看错题了.看错题害死人. 一般询问的问题,如果不能用线段树log(n)求出,那么就离线做. 首先将询问按从大到小排序,再将序列中的每个数排序,注意记录序号. 对于当前询问,每加进一个数,我需要找到它在加进的序列(按大小有序

51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)

装盒子 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 有n个长方形盒子,第i个长度为Li,宽度为Wi,我们需要把他们套放.注意一个盒子只可以套入长和宽分别不小于它的盒子,并且一个盒子里最多只能直接装入另外一个盒子 (但是可以不断嵌套),例如1 * 1 可以套入2 * 1,而2 * 1再套入2 * 2.套入之后盒子占地面积是最外面盒子的占地面积.给定N个盒子大小,求最终最小的总占地面积. Input 第一行一个数N表示盒子的个数. 接下来N行,每行两个正整数,表示每个盒子的长

51nod 算法马拉松4 B递归(YY)

递归 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 函数f(n,m) { 若n=1或m=1返回a[n][m]; 返回f(n-1,m)异或f(n,m-1); } 读入2<=n,m<=100 for i=2->100读入a[1][i] for i=2->100读入a[i][1] 输出f(n,m) 发现当n,m较大时程序变得异常缓慢. 小b经过一番思考,很快解决了这个问题. 这时小c出现了,我将n,m都增加131072,你还能解决吗? 相对的,我会读入2->13