ZOJ 2301 离散化

题目链接: 题意是说,有从 1 开始递增依次编号的很多球,开始他们都是黑色的,现在依次给出 n 个操作(ai,bi,ci),每个操作都是把编号 ai 到 bi 区间内的所有球涂成 ci 表示的颜色(黑 or 白),然后经过 n 次给定的操作后,求最长的连续白色区间的左端点和右端点。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long Ull;
#define MM(a,b) memset(a,b,sizeof(a));
const double eps = 1e-10;
const int inf = 0x3f3f3f3f;
const double pi=acos(-1);
const int maxn=100000;
int cnt;

struct node{
   ll l,r;
}ne[2*maxn+10];

bool cmp(node a,node b)
{
   if(a.l!=b.l) return a.l<b.l;
   else return a.r<b.r;
}

bool inter(node i,node j)
{
   return j.r>=i.l&&j.l<=i.r;
}

void update(node &tmp,node &j)
{
   if(tmp.l>j.l&&tmp.r<j.r)
       {
           ne[++cnt]=(node){tmp.r+1,j.r};
           j=(node){j.l,tmp.l-1};
           return;
       }

   if(tmp.l<=j.l&&tmp.r>=j.r)
      {j.l=-1;j.r=-1;return;}
   if(tmp.l>j.l)
       j.r=tmp.l-1;
   else  j.l=tmp.r+1;
}

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int l,r;
        char op[5];
        cnt=0;
        for(int i=1;i<=n;i++)
           {
               scanf("%d %d",&l,&r);
               if(l>r) swap(l,r);//题目只是说给定的范围
               scanf("%s",op);
               if(op[0]==‘w‘)
                   {ne[++cnt].l=l;ne[cnt].r=r;}
               else
               {
                   node tmp=(node){l,r};
                   int curcnt=cnt;
                   for(int j=1;j<=curcnt;j++)
                       if(inter(tmp,ne[j]))
                            update(tmp,ne[j]);
               }
           }
           sort(ne+1,ne+cnt+1,cmp);
           node ans=(node){1,0};
           for(int i=1;i<=cnt;)
               {
                   node cur=(node){ne[i].l,ne[i].r};
                   if(cur.l<0) {i++;continue;}
                   while(cur.r+1>=ne[i].l)
                    {
                        cur.r=max(ne[i].r,cur.r);i++;//注意新加入的区间不///一定r大于当前
                        if(i>cnt) break;
                    }
                   if(cur.r-cur.l+1>ans.r-ans.l+1)
                      ans=cur;
               }
           if(ans.r!=0)
               printf("%lld %lld\n",ans.l,ans.r);
           else printf("Oh, my god\n");
    }
    return 0;
}

  分析:最多int范围内的数的球,说明直接开数组是肯定不行的,考虑离散化,毕竟n<=2000,每个

节点代表一个区间,然后每次一出现一个新的黑色的节点,就考虑其对已经有的白色区间的干扰,最后

对所有的白色区间合并记录最长长度就好,参考文章;

wa代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long Ull;
#define MM(a,b) memset(a,b,sizeof(a));
const double eps = 1e-10;
const int inf = 0x3f3f3f3f;
const double pi=acos(-1);
const int maxn=100000;
int cnt;

struct node{
   ll l,r;
}ne[2*maxn+10];

bool cmp(node a,node b)
{
   if(a.l!=b.l) return a.l<b.l;
   else return a.r<b.r;
}

bool inter(node i,node j)
{
   return j.r>=i.l&&j.l<=i.r;
}

void update(node &tmp,node &j)
{
   if(tmp.l>j.l&&tmp.r<j.r)
       {
           j=(node){j.l,tmp.l-1};
           ne[++cnt]=(node){tmp.r+1,tmp.r};
           return;
       }

   if(tmp.l<=j.l&&tmp.r>=j.r)
      {j.l=-1;j.r=-1;return;}
   if(tmp.l>j.l)
       j.r=tmp.l-1;
   else  j.l=tmp.r+1;
}

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int l,r;
        char op[5];
        cnt=0;
        for(int i=1;i<=n;i++)
           {
               scanf("%d %d",&l,&r);
               scanf("%s",op);
               if(op[0]==‘w‘)
                   {ne[++cnt].l=l;ne[cnt].r=r;}
               else
               {
                   node tmp=(node){l,r};
                   for(int j=1;j<=cnt;j++)
                       if(inter(tmp,ne[j]))
                            update(tmp,ne[j]);
               }
           }
            sort(ne+1,ne+cnt+1,cmp);
            node ans=(node){0,0};
           for(int i=1;i<=cnt;)
               {
                   node cur=(node){ne[i].l,ne[i].r};
                   if(cur.l<0) continue;
                   while(inter(cur,ne[i]))
                    {cur.r=ne[i].r;i++;}
                   if(cur.r-cur.l+1>ans.r-ans.l+1)
                      ans=cur;
               }
           if(ans.l!=0&&ans.r!=0)
               printf("%d %d\n",ans.l,ans.r);
           else printf("Oh, my god\n");
    }
    return 0;
}

  

时间: 2024-10-12 19:53:59

ZOJ 2301 离散化的相关文章

HDU 1199 &amp;amp;&amp;amp; ZOJ 2301 线段树离散化

一段长度未知的线段.一种操作:a b c ,表示区间[a,b]涂为颜色C,w代表白色,b代表黑色,问终于的最长连续白色段,输出起始位置和终止位置 离散化处理.和寻常的离散化不同,须要把点化成线段.左闭右开,即对于一段区间[a.b],转化成区间[a,b+1) #include "stdio.h" #include "string.h" #include "algorithm" using namespace std; struct node { i

ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和

题意:给你n个球排成一行,初始都为黑色,现在给一些操作(L,R,color),给[L,R]区间内的求染上颜色color,'w'为白,'b'为黑.问最后最长的白色区间的起点和终点的位置. 解法:先离散化,为了防止离散后错误,不仅将L,R离散,还要加入L+1,L-1,R+1,R-1一起离散,这样就绝不会有问题了.然后建线段树,线段树维护四个值: 1.col  区间颜色  0 表示黑  1 表示白  -1表示无标记 2.maxi 区间内最大白区间的长度,由于白色用1表示,所以最大白区间的长度即为区间最

HDU 1199 &amp;&amp; ZOJ 2301 线段树离散化

一段长度未知的线段,一种操作:a b c ,表示区间[a,b]涂为颜色C,w代表白色,b代表黑色,问最终的最长连续白色段,输出起始位置和终止位置 离散化处理,和平常的离散化不同,需要把点化成线段,左闭右开,即对于一段区间[a,b],转化成区间[a,b+1) #include "stdio.h" #include "string.h" #include "algorithm" using namespace std; struct node { i

线段树 [HDU 1199] Color the Ball

Color the Ball Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4529    Accepted Submission(s): 1114 Problem Description There are infinite balls in a line (numbered 1 2 3 ....), and initially a

线段树区间更新+离散化——ZOJ 3299

对应ZOJ题目:点击打开链接 Fall the Brick Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %lld & %llu Submit Status Description Now the God is very angry, so he wants to punish the lazy, greedy humans. He chooses to throw some lines of bricks (just

ZOJ 3299-Fall the Brick(线段树+离散化)

题意: n个区间 ,给出区间的左右坐标 ,区间内填满宽度为1的箱子,有m个板子给出板子的高度和左右坐标(同高度不重叠) 所有箱子从上向下落,求每块板子能接到的箱子数. 分析: 首先给的区间很大,一开始直接存ME了,所以要先把给定的区间离散化 箱子的宽度是1则使维护区间左闭右开,才能得正确的数量. #include <map> #include <set> #include <list> #include <cmath> #include <queue&

ZOJ 3042 City Selection II 【序】【离散化】【数学】

题意: 输入数据n,m.n代表工厂的数量,m代表城市的数量. 接下来n+m行为工厂和城市的坐标. 规定如图所示方向刮风,工厂的air会污染风向地区的air. 注意,工厂和城市的坐标表示的是从x到x+1从y到y+1之间小正方形都是工厂区域,规定如果只有一个coner的air被污染那么该地区视为无污染. 要求输出有多少不被污染的城市. 坑: 思考了很多问题.... 1.加入某城市的正下方是工厂怎么办...这个是否算污染. 2.假如有两个角被污染了怎么办...算污染吗. 坑了一整天.没办法找大神的代码

zoj 3299(区间修改+离散化)

题意:有n个由小木块组成的长条木块要掉下来,给出木块的左右区间,然后有给了m个木板的左右区间和高度用来接住木块,因为木块是由小木块接触组成的,也就是木板可以接住一部分的木块,剩下的会继续掉落,问最后每个木板上有多少个小木块. 题解:这道题用线段树可解,还有另一个比较机智的做法. 先说线段树,左右区间到3×1e7,如果用线段树解决需要离散化.把木板从低到高排序后用一个线段树flag维护每个区间对应的木板编号,这样高的木板就可以覆盖低木板的编号,然后用另一个线段树sum维护每个长条木块在每个区间内的

图论 500题——主要为hdu/poj/zoj

转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并查集======================================[HDU]1213   How Many Tables   基础并查集★1272   小希的迷宫   基础并查集★1325&&poj1308  Is It A Tree?   基础并查集★1856   More i