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

题意:

一个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\n",i,tmp);
                if(flg)ans++;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wrjlinkkkkkk/p/10802731.html

时间: 2024-08-12 05:44:52

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

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 o

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

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

poj 2777 Count Color(线段树区间修改)

题目链接:http://poj.org/problem?id=2777 题目意思:就是问你在询问的区间里有几种不同的颜色 思路:这题和一般的区间修改差不多,但是唯一不同的就是我们要怎么计算有种颜色,所以这时候我们就需要把延时标记赋予不同的意义,当某段区间有多种颜色时就赋值为-1,当为一种颜色时就把它赋值为这个颜色的号数.这儿我们要怎么统计询问区间不同的颜色数叻,为了不重复计算同一种颜色,那么我们就需要用一个数组来标记计算过的颜色,当我们下次遇到时就不需要再次计算了.... 代码核心处就在计数那儿

UVALive3938 &quot;Ray, Pass me the dishes!&quot; 线段树动态区间最大和

AC得相当辛苦的一道题,似乎不难,但是需要想仔细, 开始的时候的错误思路----是受之前做过的区间最长连续子串影响http://blog.csdn.net/u011026968/article/details/38357157 区间合并的时候,我直接按照---如果(左子树的最大前缀和长度==左子树的长度 && 右子树的前缀和>0),就合并左前缀,这想法有两个错误:1.右子树的前缀和==0的时候是不是要合并区间呢?题目要求x尽量小,如果x相同y尽量小(x是ans的区间左端点,y是Ans

PKU 2777 Count Color (线段树区间更新)

题意: 给你三个数:L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000),表示有一长度为L的板(1~L), 有T种颜色(1~T),然后有O个操作,初始板1~L的颜色为1,"C A B C"表示在区间A,B图上C颜色, "P A B" 表示询问 A,B区间有几种不同的颜色. #include <stdio.h> #include <iostr

poj 2777 Count Color【线段树段更新】

题目:poj 2777 Count Color 题意:给出一段1 * n 的栅栏,有两种操作,第一种:把 l -- r 全部染成同一颜色t,第二种,查询 l---r 一共有多少种颜色. 分类:线段树 分析:我们可以给每个节点加一个标记,标记当前节点是否只有一种颜色,然后对只有一种颜色的节点如果要染色的话,那么他会变成几种颜色的,这时候记得向下更新一次就好,统计的时候统计节点有单个颜色的颜色就好. 代码: #include <cstdio> #include <cstring> #i