题意:
一个1e6*1e6的棋盘,有两个操作:给(x,y)加上颜色c,或查找(1,y1)到(x,y2)内的颜色种类数量,最多有50种颜色
思路:
建立50颗线段树,对每个颜色的线段树,维护每个y坐标上x的最小值
但是这样会爆内存,于是动态开点即可
动态开点之后T了一发,就改了下查询的函数,只要有满足在矩形的该颜色,就全线return,果然快了好多
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef long long LL; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 2e6+100; const int maxm = 2e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); int lc[maxn<<2]; int rc[maxn<<2]; int minv[maxn<<2]; int tot; int root[55]; int build(){ tot++; lc[tot]=rc[tot]=0; minv[tot]=mod; return tot; } void update(int p, int v, int l, int r, int &root){ if(!root){ root = build(); } if(minv[root] > v) minv[root] = v; if(l==r)return; int mid = (l+r)/2; if(p <= mid)update(p,v,l,mid,lc[root]); if(p > mid)update(p,v,mid+1,r,rc[root]); } int flg; int X; void query(int ql, int qr, int l, int r, int root){ if(!root||flg)return; if(ql <= l && r <= qr){ if(minv[root]<=X)flg=1; return; } int mid = (l+r)/2; if(ql <= mid)query(ql, qr, l, mid, lc[root]); if(mid < qr) query(ql, qr, mid+1,r,rc[root]); return; } int main(){ tot = 0; int op; while(scanf("%d", &op)){ if(op==3)return 0; if(op==0){ tot = 0; mem(root,0); } else if(op == 1){ int x, y, c; scanf("%d %d %d", &x, &y, &c); if(!root[c]){ root[c] = build(); } update(y, x, 1, 1000000, root[c]); } else{ int ans = 0; int x,y1,y2; scanf("%d %d %d", &x, &y1, &y2); X=x; for(int i = 0; i <= 50; i++){ flg = 0; query(y1,y2,1,1000000,root[i]); //printf("-- %d %d ",i,tmp); if(flg)ans++; } printf("%d ",ans); } } return 0; }