51nod 1768 Rikka with Sequences KDtree维护历史最大值

来源:互联网 发布:签名设计图软件 编辑:程序博客网 时间:2024/06/06 07:37

题意

众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:
勇太有一个长度为 n 的数组A 和一个大小为n×n 的二维数组B,最开始Bi,j=jk=iAk
接下来勇太进行了两种操作:
1. 给出两个整数 lx ,把 Ai 的值变成 x
2. 给出两个整数 lr ,保证 l<r ,表示询问 Bl,r 的值。
在每次操作之后,勇太都会进行一次更新:Bi,j=min(Bi,j,jk=iAk)
为了锻炼六花的计算能力,勇太希望六花能够尽可能快地回答他的问题。
当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?
输入数据保证n,m105Ai,x109

分析

要做这题首先你要会维护历史最值。如果不会的话可以先看这里。
我们可以把操作里面,把一个询问(l,r)看做二维平面上的一个点。
那么一次修改操作,就相当于把横坐标不大于l且纵坐标不小于l的点加上一个数。
这个的话可以用KDtree打标记来维护。
复杂度的话。。。不是很会证,据题解说是O(mm)

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=100005;int n,m,D,tot;LL s[N],a[N];struct tree{int d[2],mn[2],mx[2],l,r;LL add,add1,val,mn1;}t[N];struct data{int op,l,r;}q[N];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}bool cmp(tree a,tree b){    return a.d[D]<b.d[D]||a.d[D]==b.d[D]&&a.d[D^1]<b.d[D^1];}void maintain(int x,int y){    t[x].mn[0]=min(t[x].mn[0],t[y].mn[0]);    t[x].mn[1]=min(t[x].mn[1],t[y].mn[1]);    t[x].mx[0]=max(t[x].mx[0],t[y].mx[0]);    t[x].mx[1]=max(t[x].mx[1],t[y].mx[1]);}void push_add(int d,LL w){    t[d].add+=w;t[d].add1=min(t[d].add1,t[d].add);    t[d].val+=w;t[d].mn1=min(t[d].val,t[d].mn1);}void pushdown(int d){    if (t[d].l)    {        int x=t[d].l;        t[x].mn1=min(t[x].mn1,t[x].val+t[d].add1);        t[x].add1=min(t[x].add1,t[x].add+t[d].add1);        push_add(x,t[d].add);    }    if (t[d].r)    {        int x=t[d].r;        t[x].mn1=min(t[x].mn1,t[x].val+t[d].add1);        t[x].add1=min(t[x].add1,t[x].add+t[d].add1);        push_add(x,t[d].add);    }    t[d].add=t[d].add1=0;}int build(int l,int r,int DD){    D=DD;int mid=(l+r)/2;    nth_element(t+l,t+mid,t+r+1,cmp);    t[mid].mn[0]=t[mid].mx[0]=t[mid].d[0];    t[mid].mn[1]=t[mid].mx[1]=t[mid].d[1];    if (l<mid) t[mid].l=build(l,mid-1,DD^1),maintain(mid,t[mid].l);    if (r>mid) t[mid].r=build(mid+1,r,DD^1),maintain(mid,t[mid].r);    return mid;}void ins(int d,int x1,int x2,int y1,int y2,LL w){    if (t[d].mn[0]>x2||t[d].mx[0]<x1||t[d].mn[1]>y2||t[d].mx[1]<y1) return;    pushdown(d);    if (t[d].mn[0]>=x1&&t[d].mx[0]<=x2&&t[d].mn[1]>=y1&&t[d].mx[1]<=y2)    {        push_add(d,w);        return;    }    if (t[d].d[0]>=x1&&t[d].d[0]<=x2&&t[d].d[1]>=y1&&t[d].d[1]<=y2) t[d].val+=w,t[d].mn1=min(t[d].val,t[d].mn1);    if (t[d].l) ins(t[d].l,x1,x2,y1,y2,w);    if (t[d].r) ins(t[d].r,x1,x2,y1,y2,w);}LL query(int d,int x,int y,int DD){    pushdown(d);    if (t[d].d[0]==x&&t[d].d[1]==y) return t[d].mn1;    if (!DD)        if (x<t[d].d[0]||x==t[d].d[0]&&y<t[d].d[1]) return query(t[d].l,x,y,DD^1);        else return query(t[d].r,x,y,DD^1);    else        if (y<t[d].d[1]||y==t[d].d[1]&&x<t[d].d[0]) return query(t[d].l,x,y,DD^1);        else return query(t[d].r,x,y,DD^1);}int main(){    n=read();m=read();    for (int i=1;i<=n;i++) a[i]=read(),s[i]=a[i]+s[i-1];    for (int i=1;i<=m;i++)    {        q[i].op=read(),q[i].l=read(),q[i].r=read();        if (q[i].op==1) continue;        tot++;        t[tot].d[0]=q[i].l;t[tot].d[1]=q[i].r;        t[tot].val=t[tot].mn1=s[q[i].r]-s[q[i].l-1];    }    int root=build(1,tot,0);    for (int i=1;i<=m;i++)    {        if (q[i].op==1)        {            ins(root,1,q[i].l,q[i].l,n,q[i].r-a[q[i].l]);            a[q[i].l]=q[i].r;        }        else printf("%lld\n",query(root,q[i].l,q[i].r,0));    }    return 0;}
原创粉丝点击