hdu 6183 Color it (线段树 动态开点)

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.

InputThe 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.

OutputFor 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

思路:有50种颜色,对每一种颜色建一颗线段树维护,动态开点。第一种操作:使点(x,y)的颜色变为c第二种:询问(1,y1),(x,y2)两点间的颜色种类数量我们可以以y轴建线段树,横坐标为值,那么要确定两点之前是否存在某种颜色,只要询问下每个颜色在y1,y2之间最小的值(也就是横坐标).判断下最小值是否小于第二种操作给出的x,如果小于的话就代表两点间存在这种颜色。

实现代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mid int m = (l + r) >> 1
const int M = 1e6+10;
int n = 1e6,flag=0;
int sum[M],ne=0,ls[M],rs[M],rt[100];

void update(int &k,int l,int r,int p,int num){
    if(!k){   //如果当前区间未拓展,拓展并赋值
        k = ++ne;
        sum[k] = num;
    }
    sum[k] = min(sum[k],num);//当前区间有值,更新下最小值
    if(l == r)
        return ;
    mid;
    if(p <= m) update(ls[k],l,m,p,num);
    else update(rs[k],m+1,r,p,num);
}

void query(int k,int L,int R,int l,int r,int up){
    if(!k||flag) return ;
    if(L <= l&&R >= r){
        if(sum[k]<=up)
            flag = 1;
            return;
    }
    mid;
    if(L <= m) query(ls[k],L,R,l,m,up);
    if(R > m) query(rs[k],L,R,m+1,r,up);
    return ;
}

void  init(){
   memset(rt,0,sizeof(rt));
   memset(sum,0,sizeof(sum));
   memset(ls,0,sizeof(ls));
   memset(rs,0,sizeof(rs));
   ne = 0;
}
int main()
{
    int op,x,y,z;
    while(~scanf("%d",&op)){
        if(op == 0)
            init();
        else if(op == 1){
            scanf("%d%d%d",&x,&y,&z);
            update(rt[z],1,n,y,x);
        }
        else if(op == 2){
            scanf("%d%d%d",&x,&y,&z);
            int ans = 0 ;
            for(int i = 0;i <= 50;i ++){
                 flag = 0;
                 query(rt[i],y,z,1,n,x);
                 if(flag) ans++;
            }
            printf("%d\n",ans);
        }
        else return 0;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kls123/p/8992605.html

时间: 2024-10-11 07:52:32

hdu 6183 Color it (线段树 动态开点)的相关文章

hdu 6183 Color it(线段树)

题目链接:hdu 6183 Color it 题意: 在一个二维平面上有n个操作. 1. x y c 在(x,y)这点上添加一个颜色c. 2. x y1 y2 询问二维平面[1,x]~[y1,y2]上有多少不同的颜色. 题解: 由于这题在x轴每次都是询问的[1,x],所以我们开50棵线段树,对于每种颜色维护每个y坐标的最小x,查询的时候就是区间查询[y1,y2]的最小x是否小于当前查询的x. 这里由于空间有限制,要用最原始版本的线段树,动态开点. 1 #include<bits/stdc++.h

HDU6183 Color it (线段树动态开点)

题意: 一个1e6*1e6的棋盘,有两个操作:给(x,y)加上颜色c,或查找(1,y1)到(x,y2)内的颜色种类数量,最多有50种颜色 思路: 建立50颗线段树,对每个颜色的线段树,维护每个y坐标上x的最小值 但是这样会爆内存,于是动态开点即可 动态开点之后T了一发,就改了下查询的函数,只要有满足在矩形的该颜色,就全线return,果然快了好多 代码: #include<iostream> #include<cstdio> #include<algorithm> #i

BZOJ_4636_蒟蒻的数列_线段树+动态开点

Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知 道N次操作后数列中所有元素的和.他还要玩其他游戏,所以这个问题留给你解决. Input 第一行一个整数N,然后有N行,每行三个正整数a.b.k. N<=40000 , a.b.k<=10^9 Output 一个数,数列中所有元素的和 Sample Input 4 2 5 1 9 10 4 6

线段树动态开点

//zz https://blog.csdn.net/u012972031/article/details/88751811//https://www.luogu.org/problemnew/show/P3372 #include<cstdio> #include<iostream> using namespace std; const int N=300010; struct node{ int ls,rs,lazy; long long sum; }tr[N]; int ro

线段树动态开点之逆序对

对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对.求这段正整数序列中逆序对的数目.Input第一行,一个数n,表示序列中有n个数.N<=5*10^5第二行n个数,表示给定的序列.序列中每个数字不超过10^9Output给定序列中逆序对的数目.Sample Input65 4 2 6 3 1Sample Output11 #include<cstdio> #define ll long long using namespace std; const int

HDU 3308 LCIS(线段树)

Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index counting from 0)Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b]. Input T in the first line, indicating

hdu 3450 离散化+dp+线段树优化

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3450 题意: 给你一串长度为n的序列,给一个d,要求找出有几个子序列能够满足两个相邻的元素之间差值不超过d. 思路: dp.定义dp[i]表示以第i个为结束的满足条件的子序列的个数. 转移方程:dp[i]=(∑i?1j=1dp[j])+1(abs(num[i]?num[j])<=d) 答案就是dp数组的总和最后扣掉n就可以了. 此时会发现更新的时间复杂度是O(n2),这个显然是过不了的. 转移的复杂度是

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1

hdu 2795 Billboard(线段树)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10890    Accepted Submission(s): 4827 Problem Description At the entrance to the university, there is a huge rectangular billboard of