網上有好多解法,我照着LRJ的白書敲了一個板子吧,3907ms過的,這題還可以SBT過,主席樹也是可以過得。劃分樹不知道行不行,反正做法挺多。。T_T。
/****************************
* author:crazy_石頭
* date:2014/05/08
* time:3907 ms
* algorithm:Treap-求區間第大數
* Pro:POJ 2761
***************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define INF 1<<29
#define eps 1e-8
#define A system("pause")
#define rep(i,h,n) for(int i=(h);i<=(n);i++)
#define ms(a,b) memset((a),(b),sizeof(a))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL long long
#define mod 100000000
const int maxn=100000+5;
const int maxm=100+10;
struct Node
{
Node* ch[2];//定義左右子樹;
int r,v;//每個結點的隨機優先級及value;
int s;//結點總數;
Node(int v):v(v)
{
ch[0]=ch[1]=NULL;
r=rand();
s=1;
}
bool operator <(const Node& rhs)const
{
return rs;
if(ch[1]!=NULL) s+=ch[1]->s;
}
};
inline void rotate(Node* &o,int d)//d==0表示左旋,d==1表示右旋;
{
Node* k=o->ch[d^1];
o->ch[d^1]=k->ch[d];
k->ch[d]=o;
o->maintain();
k->maintain();
o=k;
}
inline void insert(Node* &o,int x)//先是普通插入,if(x_vv?0:1);//不要用cmp函數,可能會有相同結點;
insert(o->ch[d],x);//插入新結點,比較優先級進行旋轉;
if(o->ch[d]->r>o->r) rotate(o,d^1);
}
o->maintain();//維護結點o的信息;
}
inline void remove(Node* &o,int x)
{
int d=o->cmp(x);
if(d==-1)
{
Node* u=o;
if(o->ch[0]!=NULL && o->ch[1]!=NULL)
{
int d2=(o->ch[0]->r>o->ch[1]->r?1:0);
rotate(o,d2);
remove(o->ch[d2],x);
}
else
{
if(o->ch[0]==NULL) o=o->ch[1];
else o=o->ch[0];
delete u;
}
}
else
remove (o->ch[d],x);
if(o!=NULL) o->maintain();
}
//查找區間第k大數;
inline int kth(Node* o,int k)
{
if(o==NULL || k<=0 || k>o->s) return 0;
int s=(o->ch[0]==NULL? 0:o->ch[0]->s);
if(k==s+1) return o->v;
else if(k<=s) return kth(o->ch[0],k);
else return kth(o->ch[1],k-s-1);
}
struct Q
{
int l,r,k,id;
bool operator<(const Q& B)const
{
return l