不开 long long 见祖宗!!
不难发现应该是开多颗权值线段树
感觉像是把线段树拆开?有点类似 Lazytag 那样就不需要处理中间部分
然后外面部分染上你的颜色
其实就是类似主席树那个感觉嘛
口胡 → Wrong Answer
我看见了不开 long long
见祖宗
但我没想到要这么开。。。
虽然我其他地方写的 bug 也不少()
像割完原来的树没 update 啦
不知道 split 了个什么东西啦
没有写垃圾回收啦(说起来我还不会分析这东西的空间复杂度)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = (200005)<<5;
const int MINN = 200005;
int n, m, tot=0;
int Lc[MAXN], Rc[MAXN];
long long Siz[MAXN];
int Rt[MINN];
int Recy[MAXN<<5];
#define NewPnt ((Recy[0])?Recy[Recy[0]--]:++tot)
#define SegRecycle(Num) {Recy[++Recy[0]]=Num, Siz[Num]=0,Lc[Num]=0,Rc[Num]=0;}
#define SegCopy(ori, niw) {Lc[niw]=Lc[ori],Rc[niw]=Rc[ori],Siz[niw]=Siz[ori];}
#define Update(pos) {Siz[pos]=Siz[Lc[pos]]+Siz[Rc[pos]];}
void Insert(int &Pos, int L, int R, int Val, int Cnt)
{
if (!Pos) Pos = NewPnt;
Siz[Pos] += Cnt;
if (L < R)
{
int Mid = L + R >> 1;
if (Val <= Mid) Insert(Lc[Pos], L, Mid, Val, Cnt);
else Insert(Rc[Pos], Mid + 1, R, Val, Cnt);
}
}
void Split(int &Pos, int &Tar, int L, int R, int bordL, int bordR)
{
if ((!Pos) || L > bordR || R < bordL) return;
if (L >= bordL && R <= bordR)
{
Tar = Pos;
Pos = 0;
return;
}
int Mid = L + R >> 1;
Tar = NewPnt;
Split(Lc[Pos], Lc[Tar], L, Mid, bordL, bordR);
Split(Rc[Pos], Rc[Tar], Mid + 1, R, bordL, bordR);
Update(Pos);
Update(Tar);
}
void Merge(int Pos, int &Tar)
{
// cout<<Pos<<"*orz*"<<Tar<<endl;
if (!Pos) return;
if (!Tar) { Tar = Pos; return;}
Siz[Tar] += Siz[Pos];
if (Lc[Pos]) Merge(Lc[Pos], Lc[Tar]);
if (Rc[Pos]) Merge(Rc[Pos], Rc[Tar]);
SegRecycle(Pos);
// cout<<"*&*"<<Siz[Tar]<<endl;
}
long long Query_num(int Pos, int L, int R, int bordL, int bordR)
{
if (bordL > R || bordR < L || !Pos) return 0;
if (L >= bordL && R <= bordR) return Siz[Pos];
int Mid = L + R >> 1;
return Query_num(Lc[Pos], L, Mid, bordL, bordR) + Query_num(Rc[Pos], Mid + 1, R, bordL, bordR);
}
int Query_kth(int Pos, int L, int R, long long Kth)
{
//cout<<Pos<<" "<<L<<" "<<R<<" "<<Kth<<" "<< Siz[Lc[Pos]]<<" "<<Siz[Rc[Pos]]<<"kt\n";
if (!Pos) return -1;
if (L == R) return (Kth>=1)?L:-1;
if (L < R)
{
int Mid = L + R >> 1;
long long SubLef = Kth - Siz[Lc[Pos]];
if (SubLef > 0) return Query_kth(Rc[Pos], Mid + 1, R, SubLef);
return Query_kth(Lc[Pos], L, Mid, Kth);
}
}
int main()
{
scanf("%d%d", &n, &m);
Rt[0] = 1;
for (register int a, i = 1; i <= n; ++i)
{
scanf("%d", &a);
Insert(Rt[1], 1, n, i, a);
}
long long rk;
bool Failed;
for (register int opt, p, x, y, i = 1; i <= m; ++i)
{
scanf("%d", &opt);
if (opt==4) scanf("%d%lld", &p, &rk);
else scanf("%d%d", &p, &x);
if (opt!=1&&opt!=4) scanf("%d", &y);
switch(opt)
{
case 0:
// 0 p x y
/* Move "all the numbers between p and q in multiset p" to a NEW multiset. */
Split(Rt[p], Rt[++Rt[0]], 1, n, x, y);
break;
case 1:
// 1 p x
/* Move "all the numbers in multiset x" to multiset p and clear multiset x. */
Merge(Rt[x], Rt[p]);
break;
case 2:
// 2 p x y
/* add "x y's" to multiset p. */
Insert(Rt[p], 1, n, y, x);
break;
case 3:
// 3 p x y
/* QUERY: The number of the elements with values between x and y in multiset p. */
printf("%lld\n", Query_num(Rt[p], 1, n, x, y));
break;
case 4:
// 4 p x
/* QUERY: The xth-smallest number in multiset p. PRINT "-1" IF IT DOESNT EXIST */
printf("%d\n", Query_kth(Rt[p], 1, n, rk));
break;
default:break;
}
}
return 0;
}