我写了几颗fhq treap, 用它们解决了洛谷上的三个模板题 : 普通平衡树、 文艺平衡树、 线段树1.
//普通平衡树
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int tot,ls[maxn],rs[maxn],val[maxn],rnd[maxn],siz[maxn];
int rt;
int newnode(int weight)
{
val[++tot]=weight;
rnd[tot]=rand();
siz[tot]=1;
return tot;
}
void update(int k)
{
siz[k] = 1 + siz[ls[k]] + siz[rs[k]];
}
void merge(int &k,int a,int b)
{
if(!a||!b) {
k=a+b;
return;
}
if(rnd[a] < rnd[b])
{
k=a;
merge(rs[a], rs[a], b);
}
else
{
k=b;
merge(ls[b], a, ls[b]);
}
update(k);
}
void split(int k,int &a,int &b,int weight)
{
if(!k)
{
a=b=0;
return;
}
if(val[k] <= weight)
{
a=k;
split(rs[a], rs[a], b, weight);
}
else
{
b=k;
split(ls[b], a, ls[b], weight);
}
update(k);
}
int kth(int k)
{
int p=rt;
while(1)
{
if(siz[ls[p]] + 1 == k) return val[p];
else
if(siz[ls[p]] + 1 < k) k-=siz[ls[p]]+1, p=rs[p];
else
p=ls[p];
}
}
int mx(int p)
{
while(rs[p]) p=rs[p];
return val[p];
}
int mi(int p)
{
while(ls[p]) p=ls[p];
return val[p];
}
int main()
{
srand((unsigned)time(0));
int n; cin >> n;
while(n--)
{
int opt,x; scanf("%d%d",&opt,&x);
if(opt==1)
{
int a=0,b=0,nnode=newnode(x);
split(rt,a,b,x);
merge(a,a,nnode);
merge(rt,a,b);
}
if(opt==2)
{
int a=0,b=0,c=0;
split(rt,b,c,x);
split(b,a,b,x-1);
merge(b,ls[b],rs[b]);
merge(a,a,b);
merge(rt,a,c);
}
if(opt==3)
{
int a=0,b=0;
split(rt,a,b,x-1);
cout<<siz[a]+1<<'
';
merge(rt,a,b);
}
if(opt==4)
{
cout<<kth(x)<<'
';
}
if(opt==5)
{
int a=0,b=0;
split(rt,a,b,x-1);
cout<<mx(a)<<'
';
merge(rt,a,b);
}
if(opt==6)
{
int a=0,b=0;
split(rt,a,b,x);
cout<<mi(b)<<'
';
merge(rt,a,b);
}
}
return 0;
}
//文艺平衡树
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m;
int rnd[maxn],tag[maxn],ls[maxn],rs[maxn],siz[maxn],val[maxn];
int rt;
int newnode(int x)
{
val[x]=x; siz[x]=1; rnd[x]=rand();
return x;
}
void update(int k)
{
siz[k] = 1 + siz[ls[k]] + siz[rs[k]];
}
void pushdown(int k)
{
swap(ls[k], rs[k]);
tag[k]=0;
tag[ls[k]] ^= 1;
tag[rs[k]] ^= 1;
}
void merge(int &k,int a,int b)
{
if(!a||!b) {
k=a+b;
return;
}
if(rnd[a]<rnd[b])
{
k=a;
if(tag[a]) pushdown(a);
merge(rs[a],rs[a],b);
}
else
{
k=b;
if(tag[b]) pushdown(b);
merge(ls[b],a,ls[b]);
}
update(k);
}
void split(int k,int &a,int &b,int weight)
{
if(!k) {
a=b=0;
return;
}
if(tag[k]) pushdown(k);
if(siz[ls[k]] + 1 <= weight)
{
a=k;
split(rs[a],rs[a],b,weight-siz[ls[a]]-1);
}
else
{
b=k;
split(ls[b],a,ls[b],weight);
}
update(k);
}
void mid(int k)
{
if(!k) return;
if(tag[k]) pushdown(k);
mid(ls[k]);
cout<<val[k]<<' ';
mid(rs[k]);
}
int main()
{
srand((unsigned)time(0));
cin >> n >> m;
for(int i=1;i<=n;++i)
{
int nnode=newnode(i);
merge(rt,rt,nnode);
}
while(m--)
{
int l,r; scanf("%d%d",&l,&r);
int a=0,b=0,c=0;
split(rt,b,c,r);
split(b,a,b,l-1);
tag[b]^=1;
merge(b,b,c);
merge(rt,a,b);
}
mid(rt);
return 0;
}
//线段树1
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int ls[maxn],rs[maxn],siz[maxn],rnd[maxn];
long long val[maxn],sum[maxn],tag[maxn];
int tot,rt;
int newnode(long long v)
{
val[++tot]=v; sum[tot]=v; rnd[tot]=rand(); siz[tot]=1; return tot;
}
void update(int k)
{
siz[k] = siz[ls[k]] + siz[rs[k]] + 1;
sum[k] = sum[ls[k]] + sum[rs[k]] + val[k];
}
//lazy tag
void ad(int k,long long v)
{
val[k] += v;
sum[k] += siz[k] * v;
}
void pushdown(int k)
{
ad(ls[k], tag[k]); tag[ls[k]] += tag[k];
ad(rs[k], tag[k]); tag[rs[k]] += tag[k];
tag[k]=0;
}
//
void merge(int &k,int a,int b)
{
if(!a||!b) {
k=a+b;
return;
}
if(rnd[a] < rnd[b])
{
k=a;
if(tag[a]) pushdown(a);
merge(rs[a], rs[a], b);
}
else
{
k=b;
if(tag[b]) pushdown(b);
merge(ls[b], a, ls[b]);
}
update(k);
}
void split(int k,int &a,int &b,int weight)
{
if(!k) {
a=b=0;
return;
}
if(tag[k]) pushdown(k);
if(siz[ls[k]] + 1 <= weight)
{
a=k;
split(rs[a], rs[a], b, weight - siz[ls[a]] - 1);
}
else
{
b=k;
split(ls[b], a, ls[b], weight);
}
update(k);
}
int main()
{
int n,m; scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
long long x; scanf("%lld", &x);
int nnode=newnode(x);
merge(rt,rt,nnode);
}
while(m--)
{
int opt,l,r;
scanf("%d%d%d",&opt, &l, &r);
if(opt==1)
{
long long k; scanf("%lld",&k);
int a=0,b=0,c=0;
split(rt,b,c,r);
split(b,a,b,l-1);
ad(b,k); tag[b]+=k;
merge(a,a,b);
merge(rt,a,c);
}
else
{
int a=0,b=0,c=0;
split(rt,b,c,r);
split(b,a,b,l-1);
cout<<sum[b]<<'
';
merge(a,a,b);
merge(rt,a,c);
}
}
return 0;
}
两个同样长度有序数列的合并, 合并后的数列中的每一个元素都是从这两个数列中分别选出一个数相加得到的(同时它也是有序的),求合并后的数列前几个数。
当然,也可以扩展到多个有序表的合并, 两两合并即可(想一想,为什么 , 假设前k-1个有序表的合并结果是有序表S,那么S和第k个有序表的合并结果P的前几项必定是由S的前几项中的某些数和第k个有序表中的某些数组成的)
代码如下
//Rujia Liu 写哒, 不过我抄也没好好抄qwq
struct Item {
int s,b; //s=A[x] + B[b]
Item(int s,int b):s(s), b(b) {}
bool operator < (const Item& rhs) const {
return s > rhs.s;
}
};
void merge(int* A,int *B,int *C,int n) {
priority_queue<Item> pq;
for(int i=0;i<n;++i)
q.push(Item(A[i] + B[0], 0));
for(int i=0;i<n;++i) {
Item item = q.top(); q.pop();
C[i] = item.s;
int b=item.b;
if(b+1<n) q.push(Item(item.s-B[b]+B[b+1], b+1));
}
}
//LA 3027 基本带权并查集的维护
//代码来自 Rujia Liu
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 20000 + 10;
int pa[maxn], d[maxn];
int findset( int x )
{
if(pa[x] != x) {
int root = findset( pa[x] );
d[x] += d[ pa[x] ];
return pa[x] = root;
} else return x;
}
int main() {
int T; scanf("%d", &T);
while(T--) {
int n, u, v;
char cmd[9];
scanf("%d", &n);
for(int i=1;i<=n;++i) { pa[i] = i; d[i] = 0; }
// init
while( scanf("%s", cmd) && cmd[0] != 'O' ) {
if(cmd[0] == 'E') { scanf("%d", &u); findset(u); printf("%d
", &d[u]); }
if(cmd[0] == 'I') { scanf("%d%d", &u, &v); pa[u] = v; d[u] = abs(u-v) % 1000; }
}
}
return 0;
}
//某意义不明的树状数组
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000005;
int a[maxn], n;
int t[maxn], l[maxn], r[maxn];
inline int lowbit(int x) { return x & -x; }
int qy(int x)
{
int res=0;
for(;x;x-=lowbit(x)) res+=t[x];
return res;
}
int ins(int x)
{
for(;x<=n;x+=lowbit(x)) t[x] += 1;
}
int main() {
scanf("%d", &n);
for(int i=1;i<=n;++i) scanf("%d", &a[i]);
for(int i=1;i<=n;++i)
{
l[i] = qy(a[i]-1);
ins(a[i]);
}
memset(t,0,sizeof t);
for(int i=n;i>=1;--i)
{
r[i] = qy(a[i]-1);
ins(a[i]);
}
long long ans=0;
for(int i=1;i<=n;++i)
ans += (long long)l[i]*(n-i-r[i]) + (long long)r[i]*(a-1-l[i]);
cout << ans;
return 0;
}
//对序列游程编码
for(int i=1;i<=n;++i)
scanf("%d", &a[i]);
m = 0, pre = 0;
for(int i=1;i<=n;++i)
if(a[i] != a[i+1])
{
b[++m] = a[i];
siz[m] = i - pre;
pre = i;
}
//单调不降序列的静态区间众数问题
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m,q;
int a[maxn];
int b[maxn], siz[maxn];
int d[21][maxn];
int pos[maxn], l[maxn], r[maxn];
void init()
{
int L=1;
for(int i=1;i<=m;++i)
{
l[i] = L;
r[i] = L + siz[i] - 1;
for(int j=l[i];j<=r[i];++j) pos[j] = i;
L = r[i] + 1;
}
for(int i=1;i<=m;++i) d[0][i] = siz[i];
for(int k=1;k<=20;++k)
for(int i=1;i+(1<<k)-1<=n;++i)
d[k][i] = max(d[k-1][i], d[k-1][i+(1<<(k-1))]);
}
int rmq(int L,int R)
{
if(L>R) return 0;
int k=log2(R-L+1);
return max(d[k][L], d[k][R-(1<<k)+1]);
}
int calc(int L,int R)
{
return R-L+1;
}
int main()
{
int pre;
while(scanf("%d", &n) && n)
{
scanf("%d", &q);
for(int i=1;i<=n;++i)
scanf("%d", &a[i]);
m = 0, pre = 0;
for(int i=1;i<=n;++i)
if(a[i] != a[i+1])
{
b[++m] = a[i];
siz[m] = i - pre;
pre = i;
}
init();
int L,R;
while(q--)
{
scanf("%d%d", &L, &R);
if(pos[L] == pos[R])
{
cout << calc(L,R) << '
';
continue;
}
int ans = rmq(pos[L]+1, pos[R]-1);
ans = max( ans, calc(L, r[pos[L]]) );
ans = max( ans, calc(l[pos[R]], R) );
cout << ans << '
';
}
}
return 0;
}