BG
菜鸡选手跟风写题.jpg
A
这个A有点简单啊。。我们把A、B、A+B分别看作三维,那么就是裸的三维偏序问题了
一开始wa了一发因为没有管坐标相同的时候询问要在人的后面~
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define lowbit(x) (x&-x)
const int N=400005;
struct data {int x,y,z,id,typ;} p[N];
int s[N],b[N],ans[N],size;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add(int x,int v) {
for (;x<=size;x+=lowbit(x)) s[x]+=v;
}
int get(int x) {
int res=0;
for (;x;x-=lowbit(x)) res+=s[x];
return res;
}
bool cmpx(data a,data b) {
if (a.x==b.x) {
if (a.y==b.y) {
if (a.z==b.z) return a.typ<b.typ;
else return a.z>b.z;
} else return (a.y>b.y);
} else return (a.x>b.x);
}
bool cmpy(data a,data b) {
if (a.y==b.y) {
if (a.z==b.z) return a.typ<b.typ;
else return a.z>b.z;
} else return (a.y>b.y);
}
void solve(int l,int r) {
if (l==r) return ;
int mid=(l+r)>>1;
solve(l,mid);
solve(mid+1,r);
std:: sort(p+l,p+mid+1,cmpy);
std:: sort(p+mid+1,p+r+1,cmpy);
for (int i=mid+1,j=l,cnt=0;i<=r;++i) {
while (j<=mid&&p[j].y>=p[i].y) {
if (!p[j].typ) add(p[j].z,1),cnt++; j++;
}
if (p[i].typ) ans[p[i].id]+=cnt-get(p[i].z-1);
}
for (int i=mid+1,j=l;i<=r;++i) {
while (j<=mid&&p[j].y>=p[i].y) {
if (!p[j].typ) add(p[j].z,-1); j++;
}
}
}
int main(void) {
// freopen("data.in","r",stdin);
// freopen("myp.out","w",stdout);
int n=read(),m=read();
rep(i,1,n) {
p[i].x=read(),p[i].y=read();
p[i].z=p[i].x+p[i].y;
p[i].id=i,p[i].typ=0;
b[i]=p[i].z;
}
rep(i,1,m) {
int x=read(),y=read(),z=read();
p[i+n]=(data) {x,y,z,i,1};
b[i+n]=z;
}
std:: sort(b+1,b+n+m+1);
size=std:: unique(b+1,b+n+m+1)-b-1;
rep(i,1,n+m) p[i].z=std:: lower_bound(b+1,b+size+1,p[i].z)-b;
std:: sort(p+1,p+n+m+1,cmpx);
solve(1,n+m);
rep(i,1,m) printf("%d\n", ans[i]);
return 0;
}
B
没写,感觉贪心不是那么显然。先鸽着吧
C
这题非常有意思
首先我们可以找到两个点(x,y),一个点w在这条链上当且仅当Q(x,y,w)=w,那么我们就可以抠出一条链出来
考虑对这条链排序,那么比较也是基于“Q(x,a,b)返回谁谁距离x更近”这个结论做的。
于是我们就得到了一条有序的链和剩余许多棵子树,对这些子树做同样的操作,然后连起来就可以得到原树了
怎么得到y呢?当生成的树保证随机时我们可以随便选,这题不保证树随机那么我们就随机一个y。这个好像叫做随机点分治?证明的话大概是重心落在随机链上的概率 > 1 2 >\frac{1}{2} >21,于是就是 O ( n log n ) O(n\log n) O(nlogn)的了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define lowbit(x) (x&-x)
const int N=400005;
struct data {int x,y,z,id,typ;} p[N];
int s[N],b[N],ans[N],size;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add(int x,int v) {
for (;x<=size;x+=lowbit(x)) s[x]+=v;
}
int get(int x) {
int res=0;
for (;x;x-=lowbit(x)) res+=s[x];
return res;
}
bool cmpx(data a,data b) {
if (a.x==b.x) {
if (a.y==b.y) {
if (a.z==b.z) return a.typ<b.typ;
else return a.z>b.z;
} else return (a.y>b.y);
} else return (a.x>b.x);
}
bool cmpy(data a,data b) {
if (a.y==b.y) {
if (a.z==b.z) return a.typ<b.typ;
else return a.z>b.z;
} else return (a.y>b.y);
}
void solve(int l,int r) {
if (l==r) return ;
int mid=(l+r)>>1;
solve(l,mid);
solve(mid+1,r);
std:: sort(p+l,p+mid+1,cmpy);
std:: sort(p+mid+1,p+r+1,cmpy);
for (int i=mid+1,j=l,cnt=0;i<=r;++i) {
while (j<=mid&&p[j].y>=p[i].y) {
if (!p[j].typ) add(p[j].z,1),cnt++; j++;
}
if (p[i].typ) ans[p[i].id]+=cnt-get(p[i].z-1);
}
for (int i=mid+1,j=l;i<=r;++i) {
while (j<=mid&&p[j].y>=p[i].y) {
if (!p[j].typ) add(p[j].z,-1); j++;
}
}
}
int main(void) {
// freopen("data.in","r",stdin);
// freopen("myp.out","w",stdout);
int n=read(),m=read();
rep(i,1,n) {
p[i].x=read(),p[i].y=read();
p[i].z=p[i].x+p[i].y;
p[i].id=i,p[i].typ=0;
b[i]=p[i].z;
}
rep(i,1,m) {
int x=read(),y=read(),z=read();
p[i+n]=(data) {x,y,z,i,1};
b[i+n]=z;
}
std:: sort(b+1,b+n+m+1);
size=std:: unique(b+1,b+n+m+1)-b-1;
rep(i,1,n+m) p[i].z=std:: lower_bound(b+1,b+size+1,p[i].z)-b;
std:: sort(p+1,p+n+m+1,cmpx);
solve(1,n+m);
rep(i,1,m) printf("%d\n", ans[i]);
return 0;
}