传送门
这道题不强制在线,本来可以用cdq分治,bitset,kd_tree什么的乱搞,但是我刚好有封装过的treap模板,BIT模板,和两个组合起来的动态二维数点模板,不用白不用。
如何用BIT套treap动态二维数点?首先,用树状数组维护第一维,接着,对于树状数组的每个节点,维护一颗平衡树,然后就好了,代码还比较简洁的,如果手写treap的话,也就142行吧。
如果不怕常数,还可以用pb_ds,大概六七十行吧。其实pb_ds常数也不一定很大(kkksc03原话),主要是在我第一次写树套树时给我留下了不好的印象,害得我第一次usaco月赛被卡常没AK。但这题要求元素可重,所以不能用pb_ds。
最后实测2746ms(I/O优化加手写内存池,权值范围为20W,未离散化),最慢的点653ms,而标程只要1471ms,树套树果然慢
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <ctime>
#include <algorithm>
typedef long long LL;
int n,i,k,f[100010],l,j;
LL ans;
struct node{
node *l,*r;
int p,size,w;
int v;//kg
node(int _v=0):v(_v){
l=r=NULL;
p=rand();
w=size=1;
}
void maintain(){
size=w;
if(l!=NULL)size+=l->size;
if(r!=NULL)size+=r->size;
}
};
struct memorypool{
static const int n=3000000;
node a[n];
node*b[n];
int w;
inline void init(){
w=n-1;
for(int i=0;i<n;++i)b[i]=&a[i];
}
inline node*newnode(){
return b[w--];
}
inline void deletenode(node*x){
b[++w]=x;
}
}m;
class treap{
private:
node*head;
inline void lturn(node* &x){
node*t=x->r;
x->r=t->l;
t->l=x;
x->maintain();
t->maintain();
x=t;
}
inline void rturn(node* &x){
node*t=x->l;
x->l=t->r;
t->r=x;
x->maintain();
t->maintain();
x=t;
}
void ins(node* &o,int y){
if(o==NULL)o=m.newnode(),*o=node(y);
else if(y>o->v){
ins(o->r,y);
if(o->r->p>o->p)lturn(o);
}else if(y<o->v){
ins(o->l,y);
if(o->l->p>o->p)rturn(o);
}else ++o->w;
o->maintain();
}
public:
void insert(int x){
ins(head,x);
}
int nomore(int y){
node*x=head;
int ans=0,s=0;
while(x!=NULL){
s=x->w;
if(x->l!=NULL)s+=x->l->size;
if(y==x->v)return ans+s;
if(y>x->v){
ans+=s;
x=x->r;
}else x=x->l;
}
return ans;
}
};
struct treearray{
treap a[200010];
void add(int x,int y){
for(int i=x;i<=k;i+=i&-i)a[i].insert(y);
}
int query(int x,int y){
int ans=0;
for(int i=x;i;i-=i&-i)ans+=a[i].nomore(y);
return ans;
}
}t;
struct ys{
int a,b,c;
bool operator<(const ys&rhs)const{
return a<rhs.a;
}
}a[100010];
inline int getint(){
int x=0;
char c=getchar();
while(!isdigit(c))c=getchar();
for(;isdigit(c);c=getchar())x=x*10+c-48;
return x;
}
int buf[10],xb;
inline void putint(int x){
for(xb=0;x;x/=10)buf[++xb]=x%10;
for(;xb;--xb)putchar(buf[xb]+48);
}
int main(){
srand(time(0));
m.init();
n=getint();
k=getint();
for(i=1;i<=n;++i){
a[i].a=getint();
a[i].b=getint();
a[i].c=getint();
}
std::sort(a+1,a+n+1);
for(i=l=1;i<=n;){
for(;a[i].a==a[l].a;++i)
t.add(a[i].b,a[i].c);
for(j=l;j<i;++j)
++f[t.query(a[j].b,a[j].c)-1];
l=i;
}
for(i=0;i<n;++i){
if(f[i]<10)putchar(f[i]+48);
else putint(f[i]);
putchar('\n');
}
return 0;
}