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

    题目
    一个比较自然的想法是线段树维护二进制分组。
    因为我们询问的是一段连续的操作的积,所以我们可以建一棵线段树,每个节点存储当前区间各个操作的积。
    这里的操作的积指的是把一系列操作做完之后区间每个位置的变换。因为有很多连续的变换是一样的所以我们可以把它们缩起来。
    因为我们知道(k)个操作最多会把整个区间划为(2k+1)段,所以所有节点的区间的总数是(O(nlog n))级别的。
    而合并两个线段树节点的操作可以使用归并排序。
    然后我们查询就可以找到对应的(log n)的线段树上的节点,然后在每个节点存储的区间中二分找到查询的位置所在的区间,然后把所有查询到的变换乘起来就行了。
    还要注意一件事情:
    因为是强制在线,我们的操作也是一个个给出而不是一开始全部给出,所以我们需要一开始先建出空的线段树,然后新加进来一个操作,我们就把它插入到线段树上对应的(log n)个节点中去,同时pushup一下。

    #include<bits/stdc++.h>
    #define ep emplace_back
    #define pi pair<int,int>
    #define fi first
    #define se second
    #define ls p<<1
    #define rs p<<1|1
    using namespace std;
    namespace IO
    {
        char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
        void Put(char x){*oS++=x;if(oS==oT)Flush();}
        int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
        void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('
    ');}
    }
    using namespace IO;
    int max(int a,int b){return a>b? a:b;}
    const int N=100007;
    int n,m,q,ison,v[N],L[N<<2],R[N<<2];pi e(1,0),f;struct node{int l,r;pi x;node(int a=0,int b=0,pi c=e){l=a,r=b,x=c;}};
    vector<int>id[N];vector<node>t[N<<2],tmp;
    int operator<(node a,node b){return a.r<b.r;}
    pi mul(pi a,pi b){return pi(1ll*a.fi*b.fi%m,(1ll*a.se*b.fi+b.se)%m);}
    vector<node>merge(vector<node>a,vector<node>b)
    {
        vector<node>c;
        for(int i=0,j=0;i<(int)a.size()||j<(int)b.size();)
    	if(a[i].r==b[j].r) c.ep(max(a[i].l,b[j].l),a[i].r,mul(a[i].x,b[j].x)),++i,++j;
    	else if(a[i].r<b[j].r) c.ep(max(a[i].l,b[j].l),a[i].r,mul(a[i].x,b[j].x)),++i;
    	else c.ep(max(a[i].l,b[j].l),b[j].r,mul(a[i].x,b[j].x)),++j;
        return c;
    }
    void build(int p,int l,int r)
    {
        id[r].ep(p),L[p]=l,R[p]=r,t[p].ep(1,n,e);
        if(l==r) return ;int mid=(l+r)>>1;
        build(ls,l,mid),build(rs,mid+1,r);
    }
    pi query(int p,int l,int r,int x)
    {
        if(l<=L[p]&&R[p]<=r) return lower_bound(t[p].begin(),t[p].end(),(node){0,x,e})->x;
        int mid=(L[p]+R[p])>>1;
        return mul((l<=mid? query(ls,l,r,x):e),(r>mid? query(rs,l,r,x):e));
    }
    int main()
    {
        ison=read()&1,n=read(),m=read();
        for(int i=1;i<=n;++i) v[i]=read();
        q=read(),build(1,1,min(q,100000));
        for(int i=1;i<=min(q,100000);++i) reverse(id[i].begin(),id[i].end());
        for(int T=0,l,r,a,b,ans=0;q;--q)
        {
    	if(read()==1)
    	{
    	    l=read(),r=read(),a=read(),b=read(),tmp.clear(),++T;
    	    if(ison) l^=ans,r^=ans;
    	    if(l>1) tmp.ep(1,l-1,e);
    	    tmp.ep(l,r,pi(a,b));
    	    if(r<n) tmp.ep(r+1,n,e);
    	    for(int p:id[T]) t[p]=L[p]==R[p]? merge(t[p],tmp):merge(t[ls],t[rs]);
    	}
    	else
    	{
    	    l=read(),r=read(),a=read();
    	    if(ison) l^=ans,r^=ans,a^=ans;
    	    f=query(1,l,r,a),write(ans=(1ll*v[a]*f.fi+f.se)%m);
    	}
        }
        return Flush(),0;
    }
    
  • 相关阅读:
    微软职位内部推荐-Senior Development Lead
    微软职位内部推荐-Senior Program Manager
    微软职位内部推荐-Senior PM
    微软职位内部推荐-Principal Software Eng Mgr
    微软职位内部推荐-Senior Software Engineer
    mysql性能优化-慢查询分析、优化索引和配置
    MySQL慢日志查询
    spark运行模式
    scala+hadoop+spark环境搭建
    MySQL Sleep进程
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11945236.html
Copyright © 2011-2022 走看看