[bzoj1901][Zju2112]Dynamic Rankings_主席树

Dynamic Rankings bzoj-1901 Zju-2112

题目大意:给定一个n个数的序列,m个操作,支持:单点修改;查询区间k小值。

注释:$1\le n,m\le 10^4$。



想法:如果这个教树套树的话,我也没办法。

其实就是借用了树状数组的思想,我们在这里叫它...阉割树状数组把。

具体地,主席树每个节点维护的仍然是前缀权值线段树。

修改的时候将修改的点二进制lowbit分解。在分解的节点的权值线段树上直接修改。

查询时我们将所有区间(左端点-1)都二进制lowbit分解,然后每个点的sum都在delta上修改,判断进左子树还是右子树即可。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100500
int sum[N<<5],ls[N<<5],rs[N<<5],n,m,root[N<<5];
int sx[N],sy[N],v[N],maxn=1e9+10,cnt,cntx,cnty;
char ch[10];
inline int lowbit(int i){return i&(-i);}
// int build(int l,int r)
// {
// 	int pos=++cnt,mid=(l+r)>>1;
// 	if(l==r) return pos;
// 	ls[pos]=build(l,mid);
// 	rs[pos]=build(mid+1,r);
// 	return pos;
// }
int update(int pre,int l,int r,int k,int val)
{
	int pos=++cnt,mid=(l+r)>>1;
	sum[pos]=sum[pre]+val;
	ls[pos]=ls[pre]; rs[pos]=rs[pre];
	if(l==r) return pos;
	if(k<=mid) ls[pos]=update(ls[pre],l,mid,k,val);
	else rs[pos]=update(rs[pre],mid+1,r,k,val);
	return pos;
}
int query(int l,int r,int k)
{
    if(l==r) return l;
    int dlt=0,mid=(l+r)>>1;
    for(int i=1;i<=cntx;i++) dlt-=sum[ls[sx[i]]];
    for(int i=1;i<=cnty;i++) dlt+=sum[ls[sy[i]]];
    if(k<=dlt)
	{
        for(int i=1;i<=cntx;i++) sx[i]=ls[sx[i]];
        for(int i=1;i<=cnty;i++) sy[i]=ls[sy[i]];
        return query(l,mid,k);
    }
	else
	{
        for(int i=1;i<=cntx;i++) sx[i]=rs[sx[i]];
        for(int i=1;i<=cnty;i++) sy[i]=rs[sy[i]];
        return query(mid+1,r,k-dlt);
    }
}
int main()
{
    int x,y,z;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
	{
		scanf("%d",&v[i]);
		for(int j=i;j<=(n<<1);j+=lowbit(j)) root[j]=update(root[j],0,maxn,v[i],1);
	}
    for(int i=1;i<=m;i++)
	{
        scanf("%s%d%d",ch,&x,&y);
        if(ch[0]==‘C‘)
		{
            for(int j=x;j<=n;j+=lowbit(j)) root[j]=update(root[j],0,maxn,v[x],-1);
            v[x]=y;
            for(int j=x;j<=n;j+=lowbit(j)) root[j]=update(root[j],0,maxn,v[x],1);
        }
		else
		{
            scanf("%d",&z);
			cntx=cnty=0;
            for(int j=x-1;j;j-=lowbit(j)) sx[++cntx]=root[j];
            for(int j=y;j;j-=lowbit(j)) sy[++cnty]=root[j];
            printf("%d\n",query(0,maxn,z));
        }
    }
}
/*
5 3

3 2 1 4 7

Q 1 4 3

C 2 6

Q 2 5 3
*/

小结:有趣...

原文地址:https://www.cnblogs.com/ShuraK/p/9393321.html

时间: 2024-11-08 08:20:35

[bzoj1901][Zju2112]Dynamic Rankings_主席树的相关文章

BZOJ1901 Zju2112 Dynamic Rankings 【树状数组套主席树】

题目 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改 变后的a继续回答上面的问题. 输入格式 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000). 分别表示序列的长度和指令的个数. 第二行有n个数,表示a[1],a[2]--a[n],这些数都小于10^9. 接下来的m

bzoj 1901: Zju2112 Dynamic Rankings -- 主席树,树状数组,哈希

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改 变后的a继续回答上面的问题. Input 第一行有两个正整数n(1≤

zoj 2112 Dynamic Rankings(主席树&amp;动态第k大)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They

【BZOJ1901】Dynamic Rankings,树状数组套主席树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6678 Solved: 2777 [Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a

【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结点的权值线段树之间毫无关联 可以看这个:http://blog.csdn.net/popoqqq/article/details/40108669?utm_source=tuicool #include<cstdio> #include<algorithm> using namespa

ZOJ -2112 Dynamic Rankings 主席树 待修改的区间第K大

Dynamic Rankings 带修改的区间第K大其实就是先和静态区间第K大的操作一样.先建立一颗主席树, 然后再在树状数组的每一个节点开线段树(其实也是主席树,共用节点), 每次修改的时候都按照树状数组的方式去修改,并且修改那些地方.查询的时候就是查询原主席树+树状数组的值. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r&quo

BZOJ 1901 Dynamic Rankings 主席树

题目大意:可修改的区间第k小 这个主席树卡了我两天...切掉Count On A Tree 之后我就一直认为带修改的主席树是树状数组套可持久化线段树...其实我被误导了... 尼玛带修改的主席树和可持久化线段树毛关系都木有啊!!! 那就是动态的权值线段树啊啊啊啊啊啊啊!!! 好吧这里给不明白主席树的孩纸一些简介: 1.外层树状数组 2.里层线段树 3.线段树动态开节点.仅此而已.和可持久化完全没关系. 4.一个点上的线段树和其他版本毛关系都没有. 5.正常按照普通的树套树往里插就行了. 7.询问

bzoj1901(Zju2112 Dynamic Rankings)

题目链接:没有权限,进不去,题目也没法交,代码也不知道对不对,有好心人有权限帮忙交下吧QAQ 题目大意:带区间修改的第K小数 题目思路:有树套树,块状链表等优秀数据结构可以解决该题,当然我还是继续练习整体二分. 把修改操作拆开成两个操作 1.删除节点上的数 2.加入一个新数,然后更新的时候注意删除操作对树状数组的更新与插入操作相反,其他的没有难度 #include <iostream> #include <cstdio> #include <cstdlib> #incl

【分块】bzoj1901 Zju2112 Dynamic Rankings

区间k大,分块大法好,每个区间内存储一个有序表. 二分答案,统计在区间内小于二分到的答案的值的个数,在每个整块内二分.零散的暴力即可. 还是说∵有二分操作,∴每个块的大小定为sqrt(n*log2(n))比较快呢. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 int n,a[10001],num[