题解 P4879 【ycz的妹子】
_虹_
2019-01-07 21:40:33
当初比赛时候用了map,成功拿到暴力分。
其实这道题拿来练习非常不错,~~其实啥东西都能往上套~~
可以把所有【有妹子的】城市的【编号】看成一个序列,第x个妹子就是序列第k大。
那么我们只要求出动态整体第k大就好了。
~~所以怼一颗支持rank的平衡树。(变量可读性应该不错【为不加注释找借口】)~~
```cpp
#include <cstdio>
#include <vector>
#include <stack>
#ifndef nullptr
#define nullptr NULL
#endif // ! nullptr
using namespace std;
inline int max(int a, int b)
{
return a > b ? a : b;
}
inline int min(int a, int b)
{
return a < b ? a : b;
}
enum sonptr
{
ls = 0, rs = 1
};
class node
{
public:
int size;
int v;
//bool erased;
node* son[2];
node(int _v = 0) :v(_v), size(1) {
son[ls] = son[rs] = nullptr;
};
inline void update()
{
size = 1;
if (son[ls]) {
size += son[ls]->size;
}
if (son[rs]) {
size += son[rs]->size;
}
}
inline void clear()
{
v = 0;
size = 1;
son[ls] = son[rs] = nullptr;
}
inline int ls_size()const
{
return son[ls] ? son[ls]->size : 0;
}
};
const int kmaxn = 500000 + 5;
node mempool[kmaxn];
stack<node*> garbage_collector;
int mpt;
node* malloc_node(int v)
{
node* t = nullptr;
if (!garbage_collector.empty())
{
t = garbage_collector.top();
garbage_collector.pop();
t->clear();
t->v = v;
}
else if (mpt >= kmaxn)
t = new node(v);
else
{
t = &mempool[mpt++];
t->v = v;
}
return t;
}
inline void free_node(node*& p)
{
garbage_collector.push(p);
}
class balance_tree
{
balance_tree(balance_tree&);
public:
double alpha;
node* root;
vector<node*> vec;
balance_tree(double _alpha = 0.75) :alpha(_alpha), root(nullptr) {}
inline const bool bad(node* p)const
{
return max(p->ls_size(), p->son[rs] ? p->son[rs]->size : 0) > p->size*alpha;
}
node** basic_insert(int v, node*& p);
void insert(int v);
void travel(node* p);
node* rebuild(int l, int r);
bool basic_erase(int v, node*& p);//true means erased
inline bool erase(int v);
int get_rank(int v);
int get_value_by_rank(int k);
int upper_bound(int v);
int lower_bound(int v);
};
node** balance_tree::basic_insert(int v, node*& p)
{
if (!p)
{
p = malloc_node(v);
return nullptr;
}
++p->size;
node** t = basic_insert(v, p->son[(v >= p->v)]);
if (bad(p))
t = &p;
return t;
}
void balance_tree::insert(int v)
{
node** t = basic_insert(v, root);
if (t)
{
vec.clear();
vec.reserve((*t)->size + 5);
travel(*t);
*t = rebuild(0, vec.size());
}
}
void balance_tree::travel(node* p)
{
if (!p)
return;
travel(p->son[ls]);
vec.push_back(p);
travel(p->son[rs]);
}
node* balance_tree::rebuild(int l, int r)
{
if (l >= r)
return nullptr;
int mid = (l + r) >> 1;
node* t = vec[mid];
t->son[ls] = rebuild(l, mid);
t->son[rs] = rebuild(mid + 1, r);
t->update();
return t;
}
bool balance_tree::basic_erase(int v, node*& p)
{
if (p->v == v)
{
if (!(p->son[ls] && p->son[rs]))
{
free_node(p);
p = p->son[bool(p->son[rs])];
//return true;
}
else
{
--p->size;
bool c = p->ls_size() < (p->son[rs] ? p->son[rs]->size : 0);
node** t = &(p->son[c]);
c = !c;
while ((*t)->son[c])
{
--(*t)->size;
t = &(*t)->son[c];
}
p->v = (*t)->v;
free_node(*t);
*t = (*t)->son[!c];
}
return true;
}
if (basic_erase(v, p->son[v > p->v])) {
--p->size;
return true;
}
else
return false;
}
inline bool balance_tree::erase(int v)
{
return basic_erase(v, root);
}
int balance_tree::get_rank(int v)
{
int rk = 0;
node* p = root;
while (p)
{
if (v > p->v)
{
rk += p->ls_size() + 1;
p = p->son[rs];
}
else
p = p->son[ls];
}
return rk + 1;
}
int balance_tree::get_value_by_rank(int k)
{
int rk = 0;
node* p = root;
while (p)
{
if (rk + p->ls_size() + 1 < k)
{
rk += p->ls_size() + 1;
p = p->son[rs];
}
else if (rk + p->ls_size() >= k)
{
p = p->son[ls];
}
else
{
return p->v;
}
}
return 0;
}
int balance_tree::upper_bound(int v)
{
return get_value_by_rank(get_rank(v + 1));
}
int balance_tree::lower_bound(int v)
{
//cout << get_rank(v) << endl;
return get_value_by_rank(get_rank(v) - 1);
}
#define reg register
int n,m;
balance_tree sbt;
long long data[kmaxn];
long long maxjoy;
bool exist[kmaxn];
inline void read(int& i)
{
scanf("%d",&i);
}
inline void readchar(char& ch)
{
do
{
ch=getchar();
}while(ch=='\n'||ch=='\r'||ch==' ');
}
void leave(int x)
{
int pos=sbt.get_value_by_rank(x);
maxjoy-=data[pos];
data[pos]=0;
sbt.erase(pos);
exist[pos]=false;
}
int main()
{
read(n);
read(m);
for(reg int i=1;i<=n;++i)
{
//cin>>data[i];
scanf("%lld",&data[i]);
maxjoy+=data[i];
exist[i]=true;
sbt.insert(i);
}
reg char opt;
reg int x,y;
++m;
while(--m)
{
//cin>>opt;
readchar(opt);
switch(opt)
{
case 'C':
//cin>>x>>y;
read(x);
read(y);
maxjoy-=y;
data[x]-=y;
break;
case 'I':
//cin>>x>>y;
read(x);
read(y);
if(exist[x])
maxjoy-=data[x];
else{
exist[x]=true;
sbt.insert(x);
}
data[x]=y;
maxjoy+=y;
break;
case 'D':
//cin>>x;
read(x);
leave(x);
break;
case 'Q':
//cout<<maxjoy<<endl;
printf("%lld\n",maxjoy);
break;
}
}
return 0;
}
```
~~跑的没有分块快~~
补充一个分块的代码,应该还算简洁。
```cpp
// luogu-judger-enable-o2
#include <cstdio>
#include <cmath>
#define reg register
using namespace std;
const int kmaxn=500000+25;
long long data[kmaxn];
bool exist[kmaxn];
int block[kmaxn];
int belong[kmaxn];
int n,m;
int block_num,block_size;
long long maxjoy=0;
inline void leave(const int& x)
{
reg int rk=0;
for(reg int i=1;i<=block_num+10;++i)
{
if(rk+block[i]>=x)//find
{
--block[i];
i=block_size*(i-1)+1;//begin pos
for(;rk<x;++i)
{
if(exist[i])
++rk;
}
--i;
maxjoy-=data[i];
data[i]=0;
exist[i]=false;
return;
}
else
rk+=block[i];
}
}
inline void read(int& i)
{
scanf("%d",&i);
}
inline void readchar(char& ch)
{
do
{
ch=getchar();
}while(ch=='\n'||ch=='\r'||ch==' ');
}
int main()
{
read(n);
read(m);
//block_size=5;
block_size=sqrt(kmaxn-1);
block_num=(kmaxn-1)/block_size+bool((kmaxn-1)%block_size);
for(reg int i=1;i<=n;++i)
{
//cin>>data[i];
scanf("%lld",&data[i]);
maxjoy+=data[i];
exist[i]=true;
}
for(reg int i=1,j=1;i<kmaxn;++i)
{
if(i>j*block_size)
++j;
belong[i]=j;
block[j]+=exist[i];
}
reg char opt;
reg int x,y;
while(m--)
{
//cin>>opt;
readchar(opt);
switch(opt)
{
case 'C':
//cin>>x>>y;
read(x);
read(y);
maxjoy-=y;
data[x]-=y;
break;
case 'I':
//cin>>x>>y;
read(x);
read(y);
if(exist[x])
{
maxjoy-=data[x];
--block[belong[x]];
}
exist[x]=true;
data[x]=y;
maxjoy+=y;
++block[belong[x]];
break;
case 'D':
//cin>>x;
read(x);
leave(x);
break;
case 'Q':
//cout<<maxjoy<<endl;
printf("%lld\n",maxjoy);
break;
}
}
return 0;
}
```
~~线段树做法写的早,代码难看就不发了~~