题干:
Do you like painting? Little D doesn't like painting, especially messy color paintings. Now Little B is painting. To prevent him from drawing messy painting, Little D asks you to write a program to maintain following operations. The specific format of these operations is as follows.
00 : clear all the points.
11 xx yy cc : add a point which color is cc at point (x,y)(x,y).
22 xx y1y1 y2y2 : count how many different colors in the square (1,y1)(1,y1) and (x,y2)(x,y2). That is to say, if there is a point (a,b)(a,b) colored cc, that 1≤a≤x1≤a≤x and y1≤b≤y2y1≤b≤y2, then the color cc should be counted.
33 : exit.
Input
The input contains many lines.
Each line contains a operation. It may be '0', '1 x y c' ( 1≤x,y≤106,0≤c≤501≤x,y≤106,0≤c≤50 ), '2 x y1 y2' (1≤x,y1,y2≤1061≤x,y1,y2≤106 ) or '3'.
x,y,c,y1,y2x,y,c,y1,y2 are all integers.
Assume the last operation is 3 and it appears only once.
There are at most 150000150000 continuous operations of operation 1 and operation 2.
There are at most 1010 operation 0.
Output
For each operation 2, output an integer means the answer .
Sample Input
0
1 1000000 1000000 50
1 1000000 999999 0
1 1000000 999999 0
1 1000000 1000000 49
2 1000000 1000000 1000000
2 1000000 1 1000000
0
1 1 1 1
2 1 1 2
1 1 2 2
2 1 1 2
1 2 2 2
2 1 1 2
1 2 1 3
2 2 1 2
2 10 1 2
2 10 2 2
0
1 1 1 1
2 1 1 1
1 1 2 1
2 1 1 2
1 2 2 1
2 1 1 2
1 2 1 1
2 2 1 2
2 10 1 2
2 10 2 2
3
Sample Output
2
3
1
2
2
3
3
1
1
1
1
1
1
1
题目大意:
解题报告:
直接51颗线段树,按照y轴建树,然后维护x的最小值。但是直接建树会mle,所以考虑动态开点。注意不要手滑写错emmm。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 1e6 + 5;
const int INF = 0x3f3f3f3f;
struct TREE {int l,r;int minn;
} tree[MAX<<2];
int root[555],tot,flag;void pushup(int rt) {int L = tree[rt].l,R = tree[rt].r;tree[rt].minn = min(tree[L].minn,tree[R].minn);
}
void update(int &rt,int l,int r,int tar,int x) {if(rt == 0) {rt = ++tot;tree[rt].l = tree[rt].r = 0;tree[rt].minn = x;}if(l == r) {tree[rt].minn = min(tree[rt].minn,x);return;}int m = (l+r)>>1;if(tar <= m) update(tree[rt].l,l,m,tar,x);else update(tree[rt].r,m+1,r,tar,x);pushup(rt);
}
void query(int rt,int l,int r,int pl,int pr,int x) {if(flag || !rt) return ;if(pl <= l && pr >= r) {if(tree[rt].minn <= x) flag = 1;return ;}int m = (l+r)>>1;if(pl <= m) query(tree[rt].l,l,m,pl,pr,x);if(pr > m) query(tree[rt].r,m+1,r,pl,pr,x);
}
int main()
{int op;tree[0].l = tree[0].r = 0;tree[0].minn = INF;while(scanf("%d",&op)) {if(op == 3) break;if(op == 0) {for(int i = 0; i<=50; i++) root[i] =0;tot=0;}if(op == 1) {int x,y,c;scanf("%d%d%d",&x,&y,&c);update(root[c],1,1000000,y,x);}if(op == 2) {int x,y1,y2,ans = 0;scanf("%d%d%d",&x,&y1,&y2);for(int i = 0; i<=50; i++) {flag = 0;query(root[i],1,1000000,y1,y2,x);ans += flag;}printf("%d\n",ans);} }return 0 ;
}
总结:
还有一个坑啊,
tree[0].l = tree[0].r = 0;
tree[0].minn = INF;
这两步必须有,因为这里是单点更新,所以update里面的if和else只进去一个,另一边没有开点。假设进入了l并且开点了l,那么tree[rt].r=0,所以你pushup的时候直接从右孩子取值直接就变成tree[0].minn了,,所以直接就成0了,所以为了避免这一状态发生,我们要把0这个节点设置成非法节点,也就是不影响结果就可以,所以我们把tree[0].minn=INF就可以了。