zoukankan      html  css  js  c++  java
  • #46. 【清华集训2014】玄学

    题目描述

    http://uoj.ac/problem/46

    题解

    看起来像是个二维平面上%*¥¥……一下,实则不然。

    麻烦一点的话我们可以对时间轴开一颗线段树,在线段树上的每一个节点上再开一颗线段树表示在这个操作范围内的修改操作和。

    这样我们可以修改log^2查询log^2的完成。

    然而修改是区间修改,查询是单点查询,需要下传标记,数组根本开不下,UOJ上只能过2个点。

    #include<iostream>
    #include<cstdio>
    #define N 100009
    using namespace std;
    typedef long long ll;
    const int maxn=100000;
    int ls[N*100],rs[N*100],now,ans,n,m,a[N],tott,T[N<<2];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct node{
        int x,y;
        node(int xx=1,int yy=0){x=xx;y=yy;}
        inline bool size(){return x!=1||y!=0;}
        inline void clear(){x=1;y=0;} 
        node operator *(const node &b)const{return node{1ll*x*b.x%m,(1ll*b.x*y%m+1ll*b.y)%m};}
    }tr[N*100];
    inline void pushdown(int cnt){
        if(!ls[cnt])ls[cnt]=++tott;
        if(!rs[cnt])rs[cnt]=++tott;
        tr[ls[cnt]]=tr[ls[cnt]]*tr[cnt];tr[rs[cnt]]=tr[rs[cnt]]*tr[cnt];
        tr[cnt].clear();
    }
    void upd2(int &cnt,int l,int r,int L,int R,int x,int y){
        if(!cnt)cnt=++tott;
        if(l>=L&&r<=R){
            tr[cnt]=tr[cnt]*node{x,y};
            return;
        }
        if(tr[cnt].size())pushdown(cnt);
        int mid=(l+r)>>1;
        if(mid>=L)upd2(ls[cnt],l,mid,L,R,x,y);
        if(mid<R)upd2(rs[cnt],mid+1,r,L,R,x,y);
    }
    void upd(int cnt,int l,int r,int L,int R,int x,int y){
        upd2(T[cnt],1,n,L,R,x,y);
        if(l==r)return;
        int mid=(l+r)>>1;
        if(now<=mid)upd(cnt<<1,l,mid,L,R,x,y);
        else upd(cnt<<1|1,mid+1,r,L,R,x,y);
    }
    void query2(int &cnt,int l,int r,int x){
        if(!cnt)return;
        if(l==r){ans=(1ll*ans*tr[cnt].x%m+1ll*tr[cnt].y)%m;return;}
        if(tr[cnt].size())pushdown(cnt);
        int mid=(l+r)>>1;
        if(mid>=x)query2(ls[cnt],l,mid,x);
        else query2(rs[cnt],mid+1,r,x);
    }
    void query(int cnt,int l,int r,int L,int R,int x){
        if(l>=L&&r<=R){query2(T[cnt],1,n,x);return;}
        int mid=(l+r)>>1;
        if(mid>=L)query(cnt<<1,l,mid,L,R,x);
        if(mid<R)query(cnt<<1|1,mid+1,r,L,R,x);
    }
    int main(){
        int id=rd();id=id&1;
        n=rd();m=rd();
        for(int i=1;i<=n;++i)a[i]=rd();
        int x,y,k,u,v;int q=rd();
        while(q--){
            int opt=rd();
            if(opt==1){
                x=rd();y=rd();u=rd();v=rd();x^=id*ans;y^=id*ans;
                now++;
                upd(1,1,maxn,x,y,u,v); 
            }
            else{
                x=rd();y=rd();k=rd();x^=id*ans;y^=id*ans;k^=id*ans;
                ans=a[k];
                query(1,1,maxn,x,y,k);
                printf("%d
    ",ans);
            }
        }
        return 0;
    } 
    View Code

    正解非常巧妙,我们对于一个修改区间(l,r),分别开三个修改,第一维为修改的r,第二维和第三维为修改的参数,为:(l-1,1,0)(r,1,0)(n,1,0)

    这样,当查询点在l前面是,我们可以二分找到第一个r大于等于自己的修改,这样保证在任意位置都能查到正确的修改。

    那么对于两组修改,我们可以用归并排序的方式把它们归并起来。

    归并的时候,r需要去min,此时r的意思是所有位置最小是r的答案。

    这里的归并就用到了二进制分组的思想。

    假设当前有3个操作。

    我们可以再去添加一个操作。

    这样就把所有满二进制位的地方都归并起来了。

    这个操作可以用线段树维护。

    查询就找到对应节点二分一下就可以了。

    代码

    #include<iostream>
    #include<cstdio>
    #define N 100009
    using namespace std;
    typedef long long ll;
    const int maxn=100000;
    int tot,ls[N<<2],rs[N<<2],now,ans,n,m,a[N];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct node{int r,x,y;}st[N*50];
    void upd(int cnt,int l,int r,int L,int R,int x,int y){
        if(l==r){
            ls[cnt]=tot+1;
            if(L>1)st[++tot]=node{L-1,1,0};
            st[++tot]=node{R,x,y};
            if(R<n)st[++tot]=node{n,1,0};
            rs[cnt]=tot;
            return;
        }
        int mid=(l+r)>>1;
        if(now<=mid)upd(cnt<<1,l,mid,L,R,x,y);
        else upd(cnt<<1|1,mid+1,r,L,R,x,y);
        if(now<r)return;
        ls[cnt]=tot+1;
        int l1=ls[cnt<<1],r1=rs[cnt<<1],l2=ls[cnt<<1|1],r2=rs[cnt<<1|1];
        while(l1<=r1&&l2<=r2){
            st[++tot]=node{min(st[l1].r,st[l2].r),1ll*st[l1].x*st[l2].x%m,(1ll*st[l1].y*st[l2].x%m+1ll*st[l2].y)%m};
            if(st[l1].r==st[l2].r)l1++,l2++;
            else if(st[l1].r<st[l2].r)l1++;else l2++;
        }
        rs[cnt]=tot;
    }
    inline void work(int cnt,int x){
        int l=ls[cnt],r=rs[cnt],nowans=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(st[mid].r>=x)nowans=mid,r=mid-1;else l=mid+1;
        }
        ans=(1ll*ans*st[nowans].x%m+1ll*st[nowans].y)%m;
    }
    void query(int cnt,int l,int r,int L,int R,int x){
        if(l>=L&&r<=R){work(cnt,x);return;}
        int mid=(l+r)>>1;
        if(mid>=L)query(cnt<<1,l,mid,L,R,x);
        if(mid<R)query(cnt<<1|1,mid+1,r,L,R,x);
    }
    int main(){
        int id=rd();id=id&1;
        n=rd();m=rd();
        for(int i=1;i<=n;++i)a[i]=rd();
        int x,y,k,u,v;int q=rd();
        while(q--){
            int opt=rd();
            if(opt==1){
                x=rd();y=rd();u=rd();v=rd();x^=id*ans;y^=id*ans;
                now++;
                upd(1,1,maxn,x,y,u,v); 
            }
            else{
                x=rd();y=rd();k=rd();x^=id*ans;y^=id*ans;k^=id*ans;
                ans=a[k];
                query(1,1,maxn,x,y,k);
                printf("%d
    ",ans);
            }
        }
        return 0;
    } 
  • 相关阅读:
    SpringBoot应用配置常用相关视图解析器
    从Spring到SpringBoot构建WEB MVC核心配置详解
    集美大学网络15软工团队作业8分数统计
    集美大学网络15软工个人作业4分数统计
    集美大学网络15软工个人作业5分数统计
    集美大学网络15软工团队作业9分数统计
    Alpha冲刺阶段评分发布
    事后诸葛亮作业评分表
    软工网络15个人作业3-评分发布
    软工网络15个人阅读作业1-评分发布
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10421712.html
Copyright © 2011-2022 走看看