【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树套树)

http://www.lydsy.com/JudgeOnline/problem.php?id=1901

这题调了我相当长的时间,1wa1a,我是第一次写树套树,这个是树状数组套splay,在每个区间维护一棵树,然后将小于key的数量累计起来,因为这种做法不能直接找第k大,而要二分然后来判断排名是否==k-1。

ps:这里有个小地方我不能理解,是看绿云大神的代码的。就是二分那里,为什么最后还要return left,不是在二分里面当s==k-1的时候就return了吗。难道说还有其它原因??所以本题不能算ac,等绿云大神noi夺金回来了我再去问问他。。

#include <cstdio>
using namespace std;
const int N=10005, oo=~0u>>1;
#define lowbit(x) (x&-x)
struct node {
	node* ch[2], *fa;
	int key, size;
	node() { ch[0]=ch[1]=fa=0; key=size=0; }
	void pushup() { size=ch[0]->size+ch[1]->size+1; }
	bool d() { return fa->ch[1]==this; }
	void setc(node* c, bool d) { ch[d]=c; c->fa=this; }
}*null;

struct Splay {
	node* root;
	Splay() { root=null; }
	void rot(node* rt) {
		node* fa=rt->fa; bool d=rt->d();
		fa->fa->setc(rt, fa->d());
		fa->setc(rt->ch[!d], d);
		rt->setc(fa, !d);
		fa->pushup();
		if(root==fa) root=rt;
	}
	node* newnode(const int &key) {
		node* ret=new node();
		ret->key=key; ret->size=1;
		ret->ch[0]=ret->ch[1]=ret->fa=null;
		return ret;
	}
	void splay(node* rt, node* fa) {
		while(rt->fa!=fa) {
			if(rt->fa->fa==fa) rot(rt);
			else rt->d()==rt->fa->d()?(rot(rt->fa), rot(rt)):(rot(rt), rot(rt));
		}
		rt->pushup();
	}
	void insert(const int& key) {
		if(root==null) { root=newnode(key); return; }
		node* t=root;
		while(t->ch[key>t->key]!=null) t=t->ch[key>t->key];
		node* c=newnode(key);
		t->setc(c, key>t->key);
		t->pushup();
		splay(c, null);
	}
	void remove(const int &key) {
		node* t=root;
		while(t!=null && t->key!=key) t=t->ch[key>t->key];
		if(t==null) return;
		splay(t, null);
		node* rt=root->ch[0];
		if(rt==null) rt=root->ch[1];
		else {
			node* m=rt->ch[1];
			while(m!=null && m->ch[1]!=null) m=m->ch[1];
			if(m!=null) splay(m, root);
			rt=root->ch[0];
			rt->setc(root->ch[1], 1);
		}
		delete root;
		root=rt;
		root->fa=null;
		if(root!=null) root->pushup();
	}
	int rank(const int& key) {
		node* t=root;
		int ret=0;
		while(t!=null) {
			if(t->key<key) {
				ret+=t->ch[0]->size+1;
				t=t->ch[1];
			}
			else t=t->ch[0];
		}
		return ret;
	}
}*line[N], *nod[N], *q[N];

int cnt;
int getrank(int key) {
	int ret=0;
	for(int i=0; i<cnt; ++i)
		ret+=q[i]->rank(key);
	return ret;
}
int getans(int k, int l, int r) {
	int r1=r, s;
	cnt=0;
	while(l<=r1) {
		if(l<=r1-lowbit(r1)+1) {
			q[cnt++]=line[r1];
			r1-=lowbit(r1);
		}
		else {
			q[cnt++]=nod[r1];
			r1--;
		}
	}
	int left=oo+1, right=oo;
	for(int i=0; i<cnt; ++i) {
		node* p=q[i]->root;
		while(p!=null) {
			if(p->key<left) {
				p=p->ch[1];
				continue;
			}
			if(p->key>right) {
				p=p->ch[0];
				continue;
			}
			s=getrank(p->key);
			if(s==k-1) return p->key;
			if(s<k-1) {
				left=p->key;
				p=p->ch[1];
			}
			else {
				right=p->key;
				p=p->ch[0];
			}
		}
	}
	return left;
}

void init() {
	null=new node(); null->ch[0]=null->ch[1]=null->fa=null;
}
int arr[N];

int main() {
	int n, m;
	init();
	scanf("%d%d", &n, &m);
	for(int i=1; i<=n; ++i) {
		scanf("%d", &arr[i]);
		line[i]=new Splay;
		nod[i]=new Splay;
		for(int j=i-lowbit(i)+1; j<=i; ++j)
			line[i]->insert(arr[j]);
		nod[i]->insert(arr[i]);
	}
	char str[3];
	int a, b, c;
	while(m--) {
		scanf("%s", str);
		if(str[0]=='Q') {
			scanf("%d%d%d", &a, &b, &c);
			printf("%d\n", getans(c, a, b));
		}
		else {
			scanf("%d%d", &a, &b);
			c=a;
			while(c<=n) {
				line[c]->remove(arr[a]);
				line[c]->insert(b);
				c+=lowbit(c);
			}
			nod[a]->root->key=b;
			arr[a]=b;
		}
	}
	return 0;
}

 

另一种做法,树状数组套主席树,比这个快多了。

http://www.cnblogs.com/iwtwiioi/p/3929957.html

 

 


 

 

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继续回答上面的问题。你需要编一个这样的程序, 从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示 a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

Input

对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

Output

Sample Input

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

Sample Output

3
6

HINT

20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。

Source

 

posted @ 2014-07-26 21:26  iwtwiioi  阅读(653)  评论(2编辑  收藏  举报