• 【BZOJ3821】【UOJ#46】【清华集训2014】—玄学(线段树分治)


    UOJ传送门

    我们发现实际上可以不用在乎给出的xx,可以先记录一个a,ba,b的系数
    显然这个每次很好计算贡献
    显然离线的时候我们可以用线段树分治氵过去
    那在线呢?
    二进制分组?
    好像不太行得通,因为在一个组内可能只取一部分
    继续考虑线段树分治
    显然在一个操作出现之前不会被统计到
    那就可以在每次加一次操作后对于已经填满的区间pushuppushup一下

    突然发现似乎pushuppushup有点问题
    我们没有办法每个节点维护一个序列表示被怎么修改,那样是O(n2)O(n^2)

    但我们发现每次修改其实最多只会在原来的基础上增加22个区间(考虑只有左右端点会切割出多的区间,其他的都是整体增加)

    考虑对每个节点维护一个vectorvector记录一下有哪些区间
    合并信息的时候可以维护双指针

    每次询问的时候按照线段树分治的老套路
    对于一个整区间二分找到询问点的信息返回

    更具体的可以参考代码

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=100005;
    int type,n,q,tot,mod,pre,a[N];
    inline void calc(int &a,int &b,int x,int y){
    	a=1ll*a*x%mod,b=(1ll*b*x+y)%mod;
    }
    struct node{
    	int l,r,a,b;
    	node(int _l,int _r,int _a,int _b):l(_l),r(_r),a(_a),b(_b){}
    	friend inline node operator +(node a,const node &b){
    		calc(a.a,a.b,b.a,b.b);return a;
    	}
    };
    vector<node>tr[N<<2];
    #define pb push_back
    #define lc (u<<1)
    #define rc ((u<<1)|1)
    #define mid ((l+r)>>1)
    void build(int u,int l,int r){
    	tr[u].pb(node(1,n,1,0));
    	if(l==r)return;
    	build(lc,l,mid),build(rc,mid+1,r);
    }
    inline void pushup(int u){
    	tr[u].clear();
    	for(int i=0,j=0,l=0;i<tr[lc].size()&&j<tr[rc].size();){
    		int a=tr[lc][i].a,b=tr[lc][i].b;
    		calc(a,b,tr[rc][j].a,tr[rc][j].b);
    		if(tr[lc][i].r<=tr[rc][j].r){
    			tr[u].pb(node(l+1,tr[lc][i].r,a,b));
    			l=tr[lc][i].r;
    			if(tr[lc][i].r==tr[rc][j].r)i++,j++;
    			else i++;
    		}
    		else {
    			tr[u].pb(node(l+1,tr[rc][j].r,a,b));
    			l=tr[rc][j].r,j++;
    		}
    	}
    }
    bool update(int u,int l,int r,int p,node k){
    	if(l==r){
    		if(k.l!=1)tr[u].pb(node(1,k.l-1,1,0));
    		tr[u].pb(k);
    		if(k.r!=n)tr[u].pb(node(k.r+1,n,1,0));
    		return true;
    	}
    	if(p<=mid){update(lc,l,mid,p,k);return false;}
    	else{
    		bool flag=update(rc,mid+1,r,p,k);
    		if(flag)pushup(u);
    		return true;
    	}
    }
    node query(int u,int l,int r,int st,int des,int k){
    	if(st==l&&r==des){
    		int L=0,R=tr[u].size();
    		while(L<=R){
    			int mi=(L+R)>>1;
    			if(tr[u][mi].l<=k&&k<=tr[u][mi].r)return tr[u][mi];
    			if(tr[u][mi].r<k)L=mi+1;
    			else R=mi-1;
    		}
    	}
    	if(des<=mid)return query(lc,l,mid,st,des,k);
    	if(mid<st)return query(rc,mid+1,r,st,des,k);
    	return query(lc,l,mid,st,mid,k)+query(rc,mid+1,r,mid+1,des,k);	
    }
    int main(){
    	type=read()&1;
    	n=read(),mod=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	q=read();
    	while(q--){
    		int op=read(),l=read(),r=read();
    		if(type)l^=pre,r^=pre;
    		switch(op){
    			case 1:{
    				int a=read(),b=read();
    				tot++,update(1,1,N-5,tot,node(l,r,a,b));
    				break;
    			}
    			case 2:{
    				int p=read();if(type)p^=pre;
    				node now=query(1,1,N-5,l,r,p);
    				cout<<(pre=((1ll*now.a*a[p]+now.b)%mod))<<'
    ';
    				break;
    			}
    		}
    	}
    }
    
  • 相关阅读:
    ubuntu 11.04 Gnome 恢复默认的任务栏面板
    (转载)学习腾讯的产品管理之道
    (转载)项目管理之外谈项目管理
    windows 下键盘映射
    该留意的文章
    一些常用的工具
    ubuntu 11.04 old sources.list
    一个css3流程导图
    echarts雷达图
    highcharts图表
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145617.html
Copyright © 2020-2023  润新知