zoukankan      html  css  js  c++  java
  • 【bzoj2333 & luoguP3273】棘手的操作(线段树合并)

      题目传送门:bzoj2333 luoguP3273

      这操作还真“棘手”。。听说这题是可并堆题?然而我不会可并堆。于是我就写了线段数合并,然后调了一晚上,数据结构毁一生!!!QAQ……

      其实这题也可以把合并强行看成树上的关系然后dfs序后直接线段树的,然而我菜啊。。看到连边就只能想到线段树合并。

      首先用并查集维护图的连通性,然后对于每个连通块建一棵下标为点的编号的线段树,于是:

      U=合并两棵树;

      A1:单点加;

      A2:区间加;

      A3:因为是整体加,所以我们可以维护一个delta表示当前每个数被整体加了多少,然后输出时直接加上就好了;

      F1:单点查询;

      F2:区间查询;

      然而还有一个F3整体查询最大值很难处理。于是我再开了一颗线段树,维护每个连通块内的最大值,修改时顺便在上面修改信息,F3操作可以直接在树上查询。

      时间复杂度$ O(n log n) $,然而常数极大。

      两颗线段树+奇奇怪怪的维护方法,使写出来的代码膨胀到了3.6kB……然后,调试++,and then,(如果你写的不优美)MLE+TLE。经过了一番痛苦的调试后,终于过了。。。QAQ

      又臭又长的代码:

    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<algorithm>
    #define ll long long
    #define inf 0x3f3f3f3f
    #define maxn 300010
    inline ll read()
    {
        ll x=0; char c=getchar(),f=1;
        for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
        for(;'0'<=c&&c<='9';c=getchar())x=x*10+c-'0';
        return x*f;
    }
    struct segment_tree1{
        struct point{
            int lc,rc,mx,delta;
        }sgt[20*maxn];
        int tot;
        void add(int now,int l,int r,int x,int y,int k)
        {
            if(x<=l&&r<=y)sgt[now].delta+=k,sgt[now].mx+=k;
            else{
                int mid=(l+r)>>1;
                if(x<=mid){
                    if(!sgt[now].lc)sgt[now].lc=++tot;
                    add(sgt[now].lc,l,mid,x,y,k);
                }
                if(mid<y){
                    if(!sgt[now].rc)sgt[now].rc=++tot;
                    add(sgt[now].rc,mid+1,r,x,y,k);
                }
                sgt[now].mx=std::max(sgt[sgt[now].lc].mx,sgt[sgt[now].rc].mx);
                if(sgt[now].mx!=-inf)sgt[now].mx+=sgt[now].delta;
            }
        }
        int getmax(int now,int l,int r,int x,int y)
        {
            if(x<=l&&r<=y)return sgt[now].mx;
            else{
                int mid=(l+r)>>1,mx=-inf;
                if(x<=mid&&sgt[now].lc)mx=std::max(mx,getmax(sgt[now].lc,l,mid,x,y));
                if(mid<y&&sgt[now].rc)mx=std::max(mx,getmax(sgt[now].rc,mid+1,r,x,y));
                return mx+sgt[now].delta;
            }
        }
        void merge(int x,int y,int d)
        {
            d+=sgt[y].delta-sgt[x].delta;
            if(!sgt[x].lc)sgt[x].lc=sgt[y].lc,sgt[sgt[x].lc].delta+=d,sgt[sgt[x].lc].mx+=d;
            else if(sgt[y].lc)merge(sgt[x].lc,sgt[y].lc,d);
            if(!sgt[x].rc)sgt[x].rc=sgt[y].rc,sgt[sgt[x].rc].delta+=d,sgt[sgt[x].rc].mx+=d;
            else if(sgt[y].rc)merge(sgt[x].rc,sgt[y].rc,d);
            sgt[x].mx=std::max(sgt[sgt[x].lc].mx,sgt[sgt[x].rc].mx)+sgt[x].delta;
        }
    }t1;
    struct segment_tree2{
        struct point{
            int mx,delta;
        }sgt[4*maxn];
        void add(int now,int l,int r,int x,int y,int k)
        {
            if(x<=l&&r<=y)sgt[now].delta+=k,sgt[now].mx+=k;
            else{
                int mid=(l+r)>>1;
                if(x<=mid)add(now<<1,l,mid,x,y,k);
                if(mid<y)add(now<<1|1,mid+1,r,x,y,k);
                sgt[now].mx=std::max(sgt[now<<1].mx,sgt[now<<1|1].mx);
                if(sgt[now].mx!=-inf)sgt[now].mx+=sgt[now].delta;
            }
        }
        int getmax(int now,int l,int r,int x,int y)
        {
            if(x<=l&&r<=y)return sgt[now].mx;
            else{
                int mid=(l+r)>>1,mx=-inf;
                if(x<=mid)mx=std::max(mx,getmax(now<<1,l,mid,x,y));
                if(mid<y)mx=std::max(mx,getmax(now<<1|1,mid+1,r,x,y));
                return sgt[now].delta+mx;
            }
        }
    }t2;
    int rt[maxn],fa[maxn],a[maxn],delta;
    int n,m;
    char op[5];
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    int main()
    {
        n=read();
        t1.tot=0; delta=0;
        t1.sgt[0].mx=t2.sgt[0].mx=-inf;
        for(int i=1;i<=n;i++){
            a[i]=read();
            rt[i]=++t1.tot; fa[i]=i;
            t1.add(rt[i],1,n,i,i,a[i]);
            t2.add(1,1,n,i,i,a[i]);
        }
        m=read();
        for(int i=1;i<=m;i++){
            scanf("%s",op);
            if(op[0]=='U'){
                int x=read(),y=read();
                x=find(x); y=find(y);
                if(x!=y){
                    fa[y]=x; t1.merge(rt[x],rt[y],0);
                    t2.add(1,1,n,x,x,std::max(a[x],a[y])-a[x]); t2.add(1,1,n,y,y,-a[y]-inf);
                    a[x]=std::max(a[x],a[y]); a[y]=-inf;
                }
            }
            else if(op[0]=='A'){
                if(op[1]=='1'){
                    int x=read(),v=read(),fx=find(x);
                    t1.add(rt[fx],1,n,x,x,v);
                    int t=t1.getmax(rt[fx],1,n,1,n);
                    t2.add(1,1,n,fx,fx,t-a[fx]);
                    a[fx]=t;
                }
                else if(op[1]=='2'){
                    int x=read(),v=read(),fx=find(x);
                    t1.add(rt[fx],1,n,1,n,v);
                    t2.add(1,1,n,fx,fx,v);
                    a[fx]+=v;
                }
                else{
                    int v=read();
                    delta+=v;
                }
            }
            else{
                if(op[1]=='1'){
                    int x=read(),fx=find(x);
                    printf("%d
    ",t1.getmax(rt[fx],1,n,x,x)+delta);
                }
                else if(op[1]=='2'){
                    int x=read(),fx=find(x);
                    printf("%d
    ",a[fx]+delta);
                }
                else printf("%d
    ",t2.getmax(1,1,n,1,n)+delta);
            }
        }
    }
    bzoj2333 & luoguP3273

      可并堆的做法以后再补吧。。

  • 相关阅读:
    DS博客作业07--查找
    第五次作业——05图
    第四次作业——04树
    DS博客作业03--栈和队列
    DS博客作业02--线性表
    DS博客作业01--日期抽象数据类型设计与实现
    C语言博客05--指针
    C语言博客作业04--数组
    DS博客作业08--课程总结
    C语言-第0次作业
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/10099529.html
Copyright © 2011-2022 走看看