• 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树


    【BZOJ3065】带插入区间K小值

    Description

    从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i]。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间k小值。他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少。
    这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
    这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
    这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
    这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
    请你帮一帮伏特吧。
    快捷版题意:带插入、修改的区间k小值在线查询。

    Input

    第一行一个正整数n,表示原来有n只跳蚤排成一行做早操。
    第二行有n个用空格隔开的非负整数,从左至右代表每只跳蚤的弹跳力。
    第三行一个正整数q,表示下面有多少个操作。
    下面一共q行,一共三种操作对原序列的操作:(假设此时一共m只跳蚤)
    1. Q x y k: 询问从左至右第x只跳蚤到从左至右第y只跳蚤中,弹跳力第k小的跳蚤的弹跳力是多少。
        (1 <= x <= y <= m, 1 <= k <= y - x + 1)
    2. M x val: 将从左至右第x只跳蚤的弹跳力改为val。
        (1 <= x <= m)
    3. I x val: 在从左至右第x只跳蚤的前面插入一只弹跳力为val的跳蚤。即插入后从左至右第x只跳蚤是我刚插入的跳蚤。
        (1 <= x <= m + 1)

    为了体现在线操作,设lastAns为上一次查询的时候程序输出的结果,如果之前没有查询过,则lastAns = 0。
    则输入的时候实际是:
    Q _x _y _k ------> 表示 Q _x^lastAns _y^lastAns _k^lastAns
    M _x _val  ------> 表示 M _x^lastAns _val^lastAns
    I _x _val  ------> 表示 I _x^lastAns _val^lastAns
    简单来说就是操作中输入的整数都要异或上一次询问的结果进行解码。

    (祝Pascal的同学早日转C++,就不提供pascal版的描述了。)

    Output

    对于每个询问输出回答,每行一个回答。

    Sample Input

    10
    10 5 8 28 0 19 2 31 1 22
    30
    I 6 9
    M 1 11
    I 8 17
    M 1 31
    M 6 26
    Q 2 7 6
    I 23 30
    M 31 7
    I 22 27
    M 26 18
    Q 26 17 31
    I 5 2
    I 18 13
    Q 3 3 3
    I 27 19
    Q 23 23 30
    Q 5 13 5
    I 3 0
    M 15 27
    Q 0 28 13
    Q 3 29 11
    M 2 8
    Q 12 5 7
    I 30 19
    M 11 19
    Q 17 8 29
    M 29 4
    Q 3 0 12
    I 7 18
    M 29 27

    Sample Output

    28
    2
    31
    0
    14
    15
    14
    27
    15
    14

    HINT

    此题作为一个小小的研究来搞吧~做法有很多~不知道这题究竟有多少种做法。
    请自觉O(log^2n),我故意卡块状链表,块链A了的请受我深情一拜……
    A掉的同学请在Discuss里面简要说下自己的做法吧~
    原序列长度 <= 35000
    插入个数 <= 35000,修改个数 <= 70000,查询个数 <= 70000  ,0 <= 每时每刻的权值 <= 70000
    由于是OJ上的题,所以数据无梯度。为了防止卡OJ,本题只有4组数据。

    题解对于本题,直接外层替罪羊树+内层权值线段树即可,具体地:

    修改:先查一下原来的权值,将替罪羊树的路径上所有点的权值线段树中删去原来的权值,再加上新的权值即可。
    加入:直接向再路径上的所有点的权值线段树加入这个权值即可,再判一下重构。(本人写丑了,如果多个子树都失衡了,那么只重构最大的子树即可)
    查询:跟树状数组套主席树的姿势差不多,我们先在替罪羊树中将这些区间对应的log棵权值线段树(以及单点)都提取出来,然后一起二分即可。

    本题需要动态开点,数组开到2000w差不多~

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int N=70000;
    const int maxn=70010;
    struct sag
    {
    	int ls,rs,siz;
    }s[20000005];
    struct bst
    {
    	int ls,rs,siz,rt,val;
    }t[maxn];
    int p[maxn],pp[maxn],ans,root,n,m;
    char str[10];
    queue<int> q;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void updata(int l,int r,int &x,int a,int b)
    {
    	if(!x)	x=q.front(),q.pop();
    	s[x].siz+=b;
    	if(l==r)	return ;
    	int mid=(l+r)>>1;
    	if(a<=mid)	updata(l,mid,s[x].ls,a,b);
    	else	updata(mid+1,r,s[x].rs,a,b);
    }
    int build(int l,int r)
    {
    	if(l>r)	return 0;
    	int mid=(l+r)>>1,x=p[mid],i;
    	t[x].siz=r-l+1;
    	t[x].ls=build(l,mid-1),t[x].rs=build(mid+1,r);
    	for(i=l;i<=r;i++)	updata(0,N,t[x].rt,t[p[i]].val,1);
    	return x;
    }
    void del(int &x)
    {
    	if(!x)	return ;
    	del(s[x].ls),del(s[x].rs),s[x].siz=0,q.push(x),x=0;
    }
    void dfs(int x)
    {
    	if(!x)	return ;
    	dfs(t[x].ls),p[++p[0]]=x,dfs(t[x].rs),t[x].ls=t[x].rs=t[x].siz=0;
    	del(t[x].rt);
    }
    void insert(int &x,int y)
    {
    	if(!x)
    	{
    		x=n,t[x].siz=1,t[x].ls=t[x].rs=0,updata(0,N,t[x].rt,t[x].val,1);
    		return ;
    	}
    	t[x].siz++,updata(0,N,t[x].rt,t[n].val,1);
    	if(y>=t[t[x].ls].siz+1)	insert(t[x].rs,y-t[t[x].ls].siz-1);
    	else	insert(t[x].ls,y);
    	if(t[x].siz>=10&&(t[t[x].ls].siz*4<t[t[x].rs].siz*3||t[t[x].ls].siz*3>t[t[x].rs].siz*4))
    		p[0]=0,dfs(x),x=build(1,p[0]);
    }
    int getval(int x,int y)
    {
    	if(y>t[t[x].ls].siz+1)	return getval(t[x].rs,y-t[t[x].ls].siz-1);
    	if(y<=t[t[x].ls].siz)	return getval(t[x].ls,y);
    	return t[x].val;
    }
    void modify(int x,int y,int a,int b)
    {
    	updata(0,N,t[x].rt,a,-1),updata(0,N,t[x].rt,b,1);
    	if(y>t[t[x].ls].siz+1)	modify(t[x].rs,y-t[t[x].ls].siz-1,a,b);
    	else	if(y<=t[t[x].ls].siz)	modify(t[x].ls,y,a,b);
    	else	t[x].val=b;
    }
    void find(int x,int a,int b)
    {
    	if(a>b)	return ;
    	if(a==1&&b==t[x].siz)
    	{
    		p[++p[0]]=t[x].rt;
    		return ;
    	}
    	if(b<=t[t[x].ls].siz)	find(t[x].ls,a,b);
    	else	if(a>t[t[x].ls].siz+1)	find(t[x].rs,a-t[t[x].ls].siz-1,b-t[t[x].ls].siz-1);
    	else	find(t[x].ls,a,t[t[x].ls].siz),pp[++pp[0]]=t[x].val,find(t[x].rs,1,b-t[t[x].ls].siz-1);
    }
    int query(int l,int r,int x)
    {
    	if(l==r)	return l;
    	int sl=0,mid=(l+r)>>1,i;
    	for(i=1;i<=p[0];i++)	sl+=s[s[p[i]].ls].siz;
    	for(i=1;i<=pp[0];i++)	sl+=(pp[i]>=l&&pp[i]<=mid);
    	if(x>sl)
    	{
    		for(i=1;i<=p[0];i++)	p[i]=s[p[i]].rs;
    		return query(mid+1,r,x-sl);
    	}
    	for(i=1;i<=p[0];i++)	p[i]=s[p[i]].ls;
    	return query(l,mid,x);
    }
    int main()
    {
    	n=rd();
    	int i,a,b,c;
    	for(i=1;i<=20000000;i++)	q.push(i);
    	for(i=1;i<=n;i++)	t[i].val=rd(),p[i]=i;
    	root=build(1,n);
    	m=rd();
    	for(i=1;i<=m;i++)
    	{
    		scanf("%s",str),a=rd()^ans,b=rd()^ans;
    		if(str[0]=='Q')
    		{
    			c=rd()^ans,p[0]=pp[0]=0;
    			find(root,a,b);
    			ans=query(0,N,c);
    			printf("%d
    ",ans);
    		}
    		if(str[0]=='M')
    		{
    			c=getval(root,a),modify(root,a,c,b);
    		}
    		if(str[0]=='I')
    		{
    			t[++n].val=b,insert(root,a-1);
    		}
    	}
    	return 0;
    }//10 10 5 8 28 0 19 2 31 1 22  30 I 6 9 M 1 11 I 8 17 M 1 31 M 6 26 Q 2 7 6 I 23 30 M 31 7 I 22 27 M 26 18 Q 26 17 31 I 5 2 I 18 13 Q 3 3 3 I 27 19 Q 23 23 30 Q 5 13 5 I 3 0 M 15 27 Q 0 28 13 Q 3 29 11 M 2 8 Q 12 5 7 I 30 19 M 11 19 Q 17 8 29 M 29 4 Q 3 0 12 I 7 18 M 29 27
  • 相关阅读:
    nginx下根据指定路由重定向
    Ubuntu下配置apache开启https
    php+websocket搭建简易聊天室实践
    rsync + git发布项目
    nginx下配置Yii2 rewrite、pathinfo等
    新装NGINX重启,出现错误 nginx: [error] open() "/usr/local/nginx/logs/nginx.pid"
    wamp mysql服务意外停止
    PHP异步请求
    php curl_errno 60
    php开启fileinfo扩展
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7452116.html
Copyright © 2020-2023  润新知