两种操作,第一种操作给点(x,y)添加一种颜色c (x,y<=1e6,c<=50);第二种操作在(1,y1)与(x,y2)所围成的矩形里有多少种颜色。操作数<15e5
这道题刚开始自己用set都能肝过去…感觉数据有点水
这道题正解应该是用51个Y轴建线段树,记录[y1,y2]的标记为i(i从0到50)的最小值是否小于等于x,开50个线段树有点大,从claris那学了一个厉害的东西
#include<bits/stdc++.h>
using namespace std;
using LL = int64_t;
const LL mod=1e9+7;
const int maxn=15e5+5;
int T[100],l[maxn],r[maxn],v[maxn],tot=0,flag=0;
int x,y1,y2;
void update(int &num,int tl,int tr,int y,int x) {
if(num==0) {
num=++tot;
v[num]=x;
}
v[num]=min(v[num],x);
if(tl==tr) return ;
int mid=(tl+tr)/2;
if(y<=mid) update(l[num],tl,mid,y,x);
else update(r[num],mid+1,tr,y,x);
}
void query(int num,int tl,int tr) {
if(flag||num==0) return ;
if(tl>=y1&&tr<=y2) {
if(v[num]<=x) flag=1;
return ;
}
int mid=(tl+tr)/2;
if(y1<=mid) query(l[num],tl,mid);
if(y2>mid) query(r[num],mid+1,tr);
}
int main()
{
int n;
while(scanf("%d",&n)) {
if(n==3) return 0;
else if(n==0) {
for(int i=0;i<=50;i++) T[i]=0;
for(int i=0;i<=tot;i++) l[i]=r[i]=0;
tot=0;
}
else if(n==1) {
int x,y,z;scanf("%d%d%d",&x,&y,&z);
update(T[z],1,1000000,y,x);
}
else {
int num=0;scanf("%d%d%d",&x,&y1,&y2);
for(int i=0;i<=50;i++) {
query(T[i],1,1000000);
if(flag) num++,flag=0;
}
printf("%d\n",num);
}
}
return 0;
}
其中T[i]代表标记为i的值的头节点是什么,l[i]表示第i个节点的下一个左边节点是什么,r[i]表示第i个节点的下一个右边节点是什么,v[i]表示第i个节点最小值是什么。有种主席树的感觉,感觉很神奇