HDU - 6183 Color it(动态开点线段树/树状数组套动态开点线段树)
Posted Frozen_Guardian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 6183 Color it(动态开点线段树/树状数组套动态开点线段树)相关的知识,希望对你有一定的参考价值。
题目链接:点击查看
题目大意:给出一个二维平面坐标系,需要完成四种操作:
- 0:删除所有点
- 1 x y c x\\ y\\ c x y c:在点 ( x , y ) (x,y) (x,y) 处添加颜色 c c c
- 2 x y 1 y 2 x\\ y1\\ y2 x y1 y2:查询左下角为 ( 1 , y 1 ) (1,y1) (1,y1) 右上角为 ( x , y 2 ) (x,y2) (x,y2) 矩阵内有多少种不同的颜色
题目分析:点数和询问都是 1 e 5 1e5 1e5 级别的,从矩阵的左侧只能等于 1 1 1 入手,将问题转换为求 x x x 的前缀和 y y y 的区间
那么自然而然想到开 50 50 50 个树状数组套线段树单独维护每个颜色,询问时单独查询即可,但这样的空间复杂度有点炸
考虑优化,因为颜色至多有 50 50 50 种,所以将颜色状压,将线段树求 “顶点个数” 的操作转换为求 “按位或” 的操作,这样只需要开一个树状数组套线段树即可,时间复杂度是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n) 的
上面是最简单的思路,但是实现起来有一定的困难,所以考虑另一种思路
还是将每种颜色独立,每次查询我们只需要确定,是否存在着一个点 ( x x , y y ) (xx,yy) (xx,yy),满足 x x > = 1 & & x x < = x & & y y > = y 1 & & y y < = y 2 xx>=1\\ \\&\\&\\ xx<=x\\ \\&\\&\\ yy>=y1\\ \\&\\&\\ yy<=y2 xx>=1 && xx<=x && yy>=y1 && yy<=y2 即可,不难发现对于 x x x 坐标而言,有一个条件永远都满足的,所以我们不妨找出区间 [ y 1 , y 2 ] [y1,y2] [y1,y2]内的点, x x x 轴的最小值,判断其是否小于等于阈值即可,于是将题目转换为了区间求最小值,单点更新的题目了
然后就是 y y y 轴的坐标比较大,可以选择离散化或动态开点,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
代码:
动态开点:
// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
T f=1;x=0;
char ch=getchar();
while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=f;
}
template<typename T>
inline void write(T x)
{
if(x<0){x=~(x-1);putchar('-');}
if(x>9)write(x/10);
putchar(x%10+'0');
}
const int inf=1000000;
const int N=1e6+100;
struct Node {
int l,r,mmin;
}tree[N];
int cnt,root[51];
bool flag;
int newnode() {
cnt++;
tree[cnt].l=tree[cnt].r=0;
tree[cnt].mmin=inf;
return cnt;
}
void update(int &k,int l,int r,int pos,int val) {
if(!k) {
k=newnode();
}
tree[k].mmin=min(tree[k].mmin,val);
if(l==r) {
return;
}
int mid=(l+r)>>1;
if(pos<=mid) {
update(tree[k].l,l,mid,pos,val);
} else {
update(tree[k].r,mid+1,r,pos,val);
}
}
void query(int k,int l,int r,int ql,int qr,int val) {
if(!k||l>qr||r<ql||flag) {
return;
}
if(l>=ql&&r<=qr) {
if(tree[k].mmin<=val) {
flag=true;
}
return;
}
int mid=(l+r)>>1;
query(tree[k].l,l,mid,ql,qr,val);
query(tree[k].r,mid+1,r,ql,qr,val);
}
int cal(int x,int y1,int y2) {
int ans=0;
for(int i=0;i<=50;i++) {
flag=0;
query(root[i],1,inf,y1,y2,x);
ans+=flag;
}
return ans;
}
void init() {
cnt=-1;
newnode();
for(int i=0;i<=50;i++) {
root[i]=0;
}
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int op;
while(scanf("%d",&op)!=EOF&&op!=3) {
if(op==0) {
init();
} else if(op==1) {
int x,y,c;
read(x),read(y),read(c);
update(root[c],1,inf,y,x);
} else if(op==2) {
int x,y1,y2;
read(x),read(y1),read(y2);
printf("%d\\n",cal(x,y1,y2));
}
}
return 0;
}
树状数组套线段树(动态开点)
// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
T f=1;x=0;
char ch=getchar();
while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=f;
}
template<typename T>
inline void write(T x)
{
if(x<0){x=~(x-1);putchar('-');}
if(x>9)write(x/10);
putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
int cnt;
struct Seg {
struct Node {
int l,r;
LL sum;
}tree[150010*20*20];
int newnode() {
cnt++;
tree[cnt].l=tree[cnt].r=0;
tree[cnt].sum=0;
return cnt;
}
void update(int &k,int l,int r,int pos,LL val) {
if(!k) {
k=newnode();
}
tree[k].sum|=val;
if(l==r) {
return;
}
int mid=(l+r)>>1;
if(pos<=mid) {
update(tree[k].l,l,mid,pos,val);
} else {
update(tree[k].r,mid+1,r,pos,val);
}
}
LL query(int k,int l,int r,int ql,int qr) {
if(!k||l>qr||r<ql) {
return 0;
}
if(l>=ql&&r<=qr) {
return tree[k].sum;
}
int mid=(l+r)>>1;
return query(tree[k].l,l,mid,ql,qr)|query(tree[k].r,mid+1,r,ql,qr);
}
}SEG;
struct Bit {
int root[N];
void add(int x,int y,LL val) {
for(int i=x;i<N;i+=lowbit(i)) {
SEG.update(root[i],1,1e6,y,val);
}
}
LL ask(int x,int y1,int y2) {
LL ans=0;
for(int i=x;i>0;i-=lowbit(i)) {
ans|=SEG.query(root[i],1,1e6,y1,y2);
}
return ans;
}
}BIT;
int cal(LL x) {
int ans=0;
while(x) {
ans+=x&1;
x>>=1;
}
return ans;
}
void init() HDU6183 Color it 动态开点线段树
HDU - 6183 Color it(动态开点线段树/树状数组套动态开点线段树)