zoukankan      html  css  js  c++  java
  • 【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
    ", 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

  • 相关阅读:
    命令[46]
    命令[53]
    命令[48]
    命令[43]
    命令[52]
    命令[55]
    命令[41]
    MYSQL[02]大小写问题
    hdu 1811
    hdu 1829
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3870597.html
Copyright © 2011-2022 走看看