zoukankan      html  css  js  c++  java
  • 【LG P3369】郁闷的小J

    一开始只当成是练一下(mathrm{Treap})(毕竟大半年没碰过键盘了),没想到真的写出来了

    首先排除建100000棵线段树的幼稚设想

    修改操作可能有点魔幻,不妨先考虑如何维护查询操作

    因为每次只查询一种编号的书,其他操作跟线段树没什么区别

    所以有了一个大胆的设想:(mathrm{Treap})当中的元素可以换成双关键字

    具体来说,就是将书的编号作为第一关键字,书的位置作为第二关键字
    这样,同一编号的书在(mathrm{Treap})当中就是连续的,就可以查询特定区间内有多少个节点了


    再细想的话,修改本身也不难

    因为每次只替换一本书,而且很显然,每本书在(mathrm{Treap})中的两个关键字不可能完全相同

    所以,可以在一开始读入时,可以直接开一个双关键字数组,把每个位置书的编号用结构体记下来

    如果要替换掉某个位置的书,就用(mathrm{Treap})模板中的delete函数,再用前款当中的那个数组调出这个位置的书的数据,delete即可,然后再insert一次即可


    注意事项:

    • 因为delete一遍之后,(mathrm{Treap})当中的*now不会倒回去(醒醒,这不是动态开点!),所以极限情况下,该题的数据范围应该开到2e5,然后我傻乎乎地以为delete可以减少内存,炸了半小时
    • 统计区间内编号个数时,要把lower_boundupper_bound写清楚
    • 结构体套结构体的时候,少用non-static的预定义
    • 把结构体的自定义运算符写好

    #include<cstdio>
    #include<ctime>
    #include<cstdlib>
    #include<climits>
    
    const int maxn=2e5+5;
    
    struct Book
    {
    	int idx,pos;
    	bool operator < (const Book &x) const{return ( idx!=x.idx ? idx<x.idx : pos<x.pos );}
    	bool operator > (const Book &x) const{return ( idx!=x.idx ? idx>x.idx : pos>x.pos );}
    	bool operator == (const Book &x) const{return ( idx==x.idx and pos==x.pos );}
    	bool operator >= (const Book &x) const{return ( idx!=x.idx ? idx>x.idx : pos>=x.pos );}
    };
    		
    struct BT
    {
    	struct Node
    	{
    		Book v;
    		int idx,sz;
    		Node* son[2];
    		
    		void update()
    		{
    			sz=1;
    			
    			if( son[0] ) sz+=son[0]->sz;
    			if( son[1] ) sz+=son[1]->sz;return;
    		}
    	}Tree[maxn],*now=Tree;
    	
    	void rotate(Node* &r,int d)
    	{
    		Node* tmp=r->son[d^1];
    		r->son[d^1]=r->son[d^1]->son[d],tmp->son[d]=r;
    		
    		r->update();
    		r=tmp,tmp->update();return;
    	}
    	
    	void insert(Node* &r,Book v)
    	{
    		if(!r)
    		{
    			r=now++;
    			r->v=v,r->idx=rand(),r->son[0]=r->son[1]=NULL,r->sz=1;return;
    		}
    		
    		int d=( v>r->v );
    		insert(r->son[d],v);
    		
    		r->update();
    		
    		if( r->idx > r->son[d]->idx ) rotate(r,d^1);
    	}
    	
    	void del(Node* &r,Book v)
    	{
    		if(!r) return;
    		
    		if( r->v==v )
    		{
    			if( !r->son[0] and !r->son[1] ) r=NULL;
    			else if( !r->son[0] xor !r->son[1] )
    			{
    				int d=(r->son[1]!=NULL);
    				r=r->son[d];
    			}
    			else
    			{
    				int d=( r->son[0]->idx < r->son[1]->idx );
    				rotate(r,d),del(r->son[d],v);
    				
    				r->update();
    			}return;
    		}
    		
    		int d=( v>r->v );
    		del(r->son[d],v),r->update();
    	}
    	
    	int num_lower_search(Node* r,Book v)
    	{
    		if(!r) return 0;
    		
    		if( v>r->v ) return ( (r->son[0]!=NULL)?r->son[0]->sz:0 ) + 1 + num_lower_search(r->son[1],v);
    		else return num_lower_search(r->son[0],v);
    	}
    	
    	int num_upper_search(Node* r,Book v)
    	{
    		if(!r) return 0;
    		
    		if( v>=r->v ) return ( (r->son[0]!=NULL)?r->son[0]->sz:0 ) + 1 + num_upper_search(r->son[1],v);
    		else return num_upper_search(r->son[0],v);
    	}
    }bt;
    
    Book a[maxn];
    
    int main()
    {
    	srand(time(0));
    	BT::Node* root=NULL;
    	
    	int n,m;scanf("%d%d",&n,&m);
    	
    	for(int i=1;i<=n;i++)
    	{
    		a[i].pos=i,scanf("%d",&a[i].idx);
    		bt.insert(root,a[i]);
    	}
    	
    	while(m--)
    	{
    		char op;scanf(" %c",&op);
    		
    		if( op=='C' )
    		{
    			int p,id;scanf("%d%d",&p,&id);
    			bt.del(root,a[p]);
    			
    			a[p].idx=id;
    			bt.insert(root,a[p]);
    		}
    		else
    		{
    			int l,r,id;scanf("%d%d%d",&l,&r,&id);
    			Book L=(Book){id,l},R=(Book){id,r};
    			
    			printf("%d
    ",bt.num_upper_search(root,R)-bt.num_lower_search(root,L));
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    Linux搭建测试环境详细步骤
    MongoDB基本查询
    数据库常用sql语句
    Js apply和call
    js中的事件委托
    javascript中的事件处理
    <a>标签的属性
    js中预加载图片
    Yahoo团队:网站性能优化的35条黄金准则
    js中用到的正则表达式
  • 原文地址:https://www.cnblogs.com/info---tion/p/13378046.html
Copyright © 2011-2022 走看看