【bzoj3600】没有人的算术

3600: 没有人的算术

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 1118   Solved: 452
[ Submit][ Status][ Discuss]

Description

Input

Output

Sample Input

Sample Output

HINT

Source

[ Submit][ Status][ Discuss]

。。。。神。。神题。。。


具体过程太抽象了。。。我们考虑如果能有一种方法能快速得到排名那就方便多了

考虑用一个平衡树维护排名,

用实数表示排名,对于每一个平衡树上的节点,用这个节点的所属实数区间的中位数作为排名;对于实数区间(根的实数区间自己定),对于右儿子,区间为(mid,r),左儿子区间为(l,mid)

每个节点在保存实数排名的同时,也要保存之前赋值的(l,r)(注意是保存l、r,而不是l、r的实数排名)

然后插入时只需要做平衡树的普通插入即可,

询问用一个线段树维护,每个节点存最大值的下标(即答案)

对于平衡树的选择,因为实数区间要相对静止,所以考虑用替罪羊树

有一个小技巧:可以维护一个id数组表示每个原数组位置现在对应的是替罪羊树上的哪个节点,从而来避免替罪羊树的删除操作(同时也是为了维护相对静止),然后线段树在比较的时候就是比较id的实数排名就好了


PS.我这个板子好像跑很快?


代码:

#include<queue>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<cstdlib>
using namespace std;

typedef long long LL;
typedef double DL;

const int INF =	20011209;
const int maxn = 500010;

DL f[maxn];

struct data{
	int x,y;
	data(int _x = 0,int _y = 0){x = _x; y = _y;}
	bool operator == (const data &b) const
	{
		return f[x] == f[b.x] && f[y] == f[b.y];
	}
	bool operator < (const data &b) const
	{
		return f[x] < f[b.x] || (f[x] == f[b.x] && f[y] < f[b.y]); 
	}
	bool operator > (const data &b) const
	{
		return f[x] > f[b.x] || (f[x] == f[b.x] && f[y] > f[b.y]);
	}
}val[maxn];

int n,m,rt,cnt;
int cur[maxn],id[maxn];
int siz[maxn],ch[maxn][2],tot;
int stk[maxn],now,p;

inline LL getint()
{
    LL ret = 0,f = 1;
    char c = getchar();
    while (c < '0' || c > '9') 
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
        ret = ret * 10 + c - '0',c = getchar();
    return ret * f;
}

inline bool bal(int o)
{
	return max(siz[ch[o][1]],siz[ch[o][0]]) <= 0.77 * siz[o];
}

inline void maintain(int o)
{
	siz[o] = siz[ch[o][1]] + siz[ch[o][0]] + 1;
}

inline void dfs(int o)
{
	if (!o) return;
	dfs(ch[o][0]);
	stk[++now] = o;
	dfs(ch[o][1]);
}

inline void rebuild(int &o,int l,int r,DL xl,DL xr)
{
	if (l > r) return;
	int mid = l + r >> 1;
	o = stk[mid]; siz[o] = 1; f[o] = (xl + xr) / 2;
	ch[o][0] = ch[o][1] = 0;
	if (l == r) return;
	rebuild(ch[o][0],l,mid - 1,xl,(xl + xr) / 2);
	rebuild(ch[o][1],mid + 1,r,(xl + xr) / 2,xr);
	maintain(o);
	return;
}

inline void Rebuild(int &p,DL L,DL R)
{
	dfs(p);
	rebuild(p,1,now,L,R);
	now = 0;
}

inline int insert(int &o,DL l,DL r,data x)
{
	if (!o) {val[o = ++tot] = x; f[o] = (l + r) / 2.0; maintain(o);}
	if (x == val[o]) return o;
	int d = x > val[o],ret = 0;
	if (!d) ret = insert(ch[o][d],l,(l + r) / 2.0,x);
	else ret = insert(ch[o][d],(l + r) / 2.0,r,x);
	maintain(o);
	if (!bal(o)) Rebuild(o,l,r);
	return ret;
}

inline int idmax(int a,int b)
{
	return f[cur[a]] >= f[cur[b]] ? a : b;
}

inline void update(int o,int l,int r,int pos)
{
	if (l == r) {id[o] = l; return;}
	int mid = l + r >> 1,lc = o << 1,rc = o << 1 | 1;
	if (pos <= mid) update(lc,l,mid,pos);
	else update(rc,mid + 1,r,pos);
	id[o] = idmax(id[lc],id[rc]);
}

inline int query(int o,int l,int r,int al,int ar)
{
	if (al <= l && r <= ar) return id[o];
	int ret = 0,mid = l + r >> 1,lc = o << 1,rc = o << 1 | 1;
	if (al <= mid) ret = idmax(ret,query(lc,l,mid,al,ar));
	if (mid < ar) ret = idmax(ret,query(rc,mid + 1,r,al,ar));
	return ret;
}

inline char getcom()
{
	char c = getchar();
	while (c != 'Q' && c != 'C') c = getchar();
	return c;
}

int main()
{
    n = getint(); m = getint();
    f[rt = ++tot] = (0 + INF) / 2.0; 
    val[rt] = (data){0,INF};
	siz[tot] = 1;
    f[0] = -1;
    for (int i = 1; i <= n; i++) update(1,1,n,i);
    for (int i = 1; i <= n; i++) cur[i] = 1;
    for (int i = 1; i <= m; i++)
    {
    	char c = getcom();
    	int l = getint(),r = getint();
    	if (c == 'Q') printf("%d\n",query(1,1,n,l,r));
	else 
	{
		int k = getint();
		cur[k] = insert(rt,0,INF,(data){cur[l],cur[r]});
		update(1,1,n,k);
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/joky_2002/article/details/79580271
今日推荐