zoukankan      html  css  js  c++  java
  • 【线段树】【CF19D】 Points

    传送门

    Description

    在一个笛卡尔坐标系中,定义三种操作:

    (add(x,y)),将点((x,y))标记在坐标系上

    (find(x,y)),查询点((x,y))严格右上方中,横坐标最小的点。如果有多个,输出其中纵坐标最小的。没有则输出-1

    (remove(x,y)),将点((x,y))取消标记

    Input

    第一行是操作个数(n)

    下面(n)行,每行对应一个操作。

    Output

    每个查询操作输出一个答案。

    Hint

    (n~leq~10^5,|x|,|y|~leq~10^9)。数据保证合法。

    Solution

    (x,y)这么大,先给他离散化再说。

    考虑一个笛卡尔坐标系上,对每个横坐标(x)任取一个(y)组成点((x,y)),是与一个数列(A)有一一对应关系的。即,点((x,y))对应序列(A_x=y)

    考虑对于一次查询,一列能做为答案的必要条件是这一列上(y)轴最大的点大于被查询的点的纵坐标。于是就想到将每个(x)对应的最大的(y)写入序列。于是每次查询时在序列上查询大于(x)的后缀上第一个大于(y)的位置的下标。这个显然可以用线段树搞定。考虑剩下的(y)怎么记录。使用线段树可以查询出应该被选择的横坐标。则纵坐标就是这一列上大于(y)的第一个数。于是对于每一列开一个(set),维护这一列上所有的(y),查询时直接upper_bound即可。

    考虑线段树的写法。对于线段树的一个区间,维护这段区间中最大值的下标是多少。查询时,先递归查询左区间,如果左区间不合法则递归查询右区间。一个区间不合法当且仅当他与被查询的区间无交或他的最大值小于被查询的值(k)

    考虑这么做的复杂度:因为一个区间会被线段树划分成(O(log(len)))个线段。发现这些遍历这些线段是(O(log))的,于是一次操作的复杂度是(O(log))的。总复杂度(O(nlogn))

    Code

    #include<set>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define rg register
    #define ci const int
    #define cl const long long
    
    typedef long long int ll;
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch=getchar(),lst=' ';
    	while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
    	while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	if(lst == '-') x=-x;
    }
    
    namespace IO {
    	char buf[120];
    }
    
    template <typename T>
    inline void qw(T x,const char aft,const bool pt) {
    	if(x < 0) {x=-x,putchar('-');}
    	rg int top=0;
    	do {IO::buf[++top]=x%10+'0';} while(x/=10);
    	while(top) putchar(IO::buf[top--]);
    	if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T a,const T b) {return a > b ? a : b;}
    template <typename T>
    inline T mmin(const T a,const T b) {return a < b ? a : b;}
    template <typename T>
    inline T mabs(const T a) {return a < 0 ? -a : a;}
    
    template <typename T>
    inline void mswap(T &_a,T &_b) {
    	T _temp=_a;_a=_b;_b=_temp;
    }
    
    const int maxn = 200010;
    const int maxt = 1600010;
    
    struct M {
    	int opt,x,y;
    };
    M MU[maxn];
    
    int n,tcnt,num;
    int temp[maxt],CU[maxt];
    std::set<int>ss[maxt];
    
    struct Tree {
    	int v;
    	inline void update(const Tree &_ls,const Tree _rs) {
    		if(!(~(_ls.v))) this->v = _rs.v;
    		else if(!(~(_rs.v))) this->v = _ls.v;
    		else {
    			if(CU[_ls.v] >= CU[_rs.v]) this->v=_ls.v;
    			else this->v=_rs.v;
    		}
    	}
    };
    Tree tree[maxt];
    
    void init_hash();
    void change(ci,ci,ci,ci);
    int ask(ci,ci,ci,ci,ci);
    
    int main() {
    	qr(n);
    	for(rg int i=1;i<=n;++i) {
    		M &now=MU[i];
    		rg char ch=getchar();
    		while((ch > 'z') || (ch < 'a')) ch=getchar();
    		if(ch == 'a') now.opt=1;
    		else if(ch == 'r') now.opt=3;
    		else now.opt=2;
    		qr(now.x);qr(now.y);
    		temp[++tcnt]=now.x;temp[++tcnt]=now.y;
    	}
    	init_hash();
    	memset(tree,-1,sizeof tree);
    	for(rg int i=1;i<=n;++i) {
    		M &now=MU[i];
    		switch(now.opt) {
    			case 1: {
    				ss[now.x].insert(now.y);
    				if(now.y == *(--ss[now.x].end())) {CU[now.x]=now.y;change(1,num,1,MU[i].x);}
    				break;
    			}
    			case 2: {
    				int k=ask(1,num,1,now.x+1,now.y);
    				if(!(~k)) {puts("-1");break;}
    				qw(temp[k],' ',true);
    				std::set<int>::iterator zay = ss[k].upper_bound(now.y);
    				qw(temp[*zay],'
    ',true);
    				break;
    			}
    			case 3: {
    				if(now.y == *(--ss[now.x].end())) {
    					ss[now.x].erase(now.y);
    					if(ss[now.x].empty()) CU[now.x]=0;
    					else CU[now.x]=*(--ss[now.x].end());
    					change(1,num,1,MU[i].x);
    				}
    				else ss[now.x].erase(now.y);
    				break;
    			}
    		}
    	}
    	return 0;
    }
    
    void init_hash() {
    	std::sort(temp+1,temp+1+tcnt);s
    	int *ed=std::unique(temp+1,temp+1+tcnt);
    	num=ed-temp-1;
    	for(rg int i=1;i<=n;++i) {
    		MU[i].x=std::lower_bound(temp+1,ed,MU[i].x)-temp;
    		MU[i].y=std::lower_bound(temp+1,ed,MU[i].y)-temp;
    	}
    }
    
    void change(ci l,ci r,ci p,ci aim) {
    	if(l > r) return;
    	if((l > aim) || (r < aim)) return;
    	if(l == r) {tree[p].v=l;return;}
    	int mid=(l+r)>>1,dp=p<<1,ddp=dp|1;
    	change(l,mid,dp,aim);change(mid+1,r,ddp,aim);
    	tree[p].update(tree[dp],tree[ddp]);
    }
    
    int ask(ci l,ci r,ci p,ci aim,ci v) {
    	if(l > r) return -1;
    	if(r < aim) return -1;
    	if(!(~(tree[p].v))) return -1;
    	if(CU[tree[p].v] <= v) return -1;
    	if(l == r) return tree[p].v;
    	int mid=(l+r)>>1,dp=p<<1,ddp=dp|1;
    	if(mid >= r) return ask(l,mid,dp,aim,v);
    	else if(mid < l) return ask(mid+1,r,ddp,aim,v);
    	else {
    		int _ans;
    		if(~(_ans=ask(l,mid,dp,aim,v))) return _ans;
    		else return ask(mid+1,r,ddp,aim,v);
    	}
    }
    

    Solution

    一个笛卡尔坐标系中对于每一个横坐标(x)选择一个纵坐标(y)后,可以将之一一对应到一个下标为(x),值为(y)的线段上。利用这个性质可以将坐标问题改为序列修改问题使用数据结构处理。

  • 相关阅读:
    C++中使用多线程
    hdu 4223 dp 求连续子序列的和的绝对值最小值
    hdu 1372 bfs 计算起点到终点的距离
    hdu 4217 线段树 依次取第几个最小值,求其sum
    心得
    hdu 1175 bfs 按要求进行搜索,是否能到达,抵消两个(相同)棋子
    hdu 4221 greed 注意范围 工作延期,使整个工作时间罚时最少的单个罚时最长的值
    hdu 2844 多重背包 多种硬币,每一种硬币有一点数量,看他能组成多少种钱
    uva LCDDisplay
    hdu 4218 模拟 根据一个圆点和半径画一个圆 注意半径要求
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9879467.html
Copyright © 2011-2022 走看看