区间合并 --- Codeforces 558D : Gess Your Way Out ! II

D. Guess Your Way Out! II

Problem‘s Link: http://codeforces.com/problemset/problem/558/D



Mean:

一棵满二叉树,树中某个叶子节点是出口,目的是寻找这个出口。再给定Q个询问的结果,每个结果告诉我们在第i层中(l,r)覆盖的叶结点是否包含出口。

analyse:

基本思路:多个区间求交集。

具体实现:

对于每一个询问,把它转化到最底层。并且把不在(l,r)区间的询问改为在(最左边,l-1)和(r+1,最右边)的形式,这样一来全部都变成了在(l,r)区间的描述。

区间统计:

对左右区间起点和终点组成的集合进行排序。然后找到答案存在的区间,如果区间长度=1,答案唯一;长度>1,答案不唯一;长度=0,无解。

Trick:会爆int。

Time complexity: O(n)

Source code: 

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-07-16-11.55
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using namespace std;
LL L[51], R[51];
int main()
{
      ios_base::sync_with_stdio( false );
      cin.tie( 0 );
      L[1] = 1, R[1] = 1;
      for( int i = 2; i <= 50; ++i ) L[i] = L[i - 1] << 1, R[i] = ( L[i] << 1 ) - 1;
      int h, q;
      cin >> h >> q;
      if( q == 0 )
      {
            if( h == 1 ) puts( "1" );
            else puts( "Data not sufficient!" );
            return 0;
      }
      map<LL, int> mp;
      for( int i = 0; i < q; ++i )
      {
            LL level, left, right, type, gap;
            cin >> level >> left >> right >> type;
            gap = h - level;
            while( gap )
            {
                  gap--;
                  left <<= 1;
                  right = ( ( right + 1 ) << 1 ) - 1;
            }
            if( type )
            {
                  mp[left]++;
                  mp[right + 1]--;
            }
            else
            {
                  mp[L[h]]++;
                  mp[left]--;
                  mp[right + 1]++;
                  mp[R[h] + 1]--;
            }
      }
      LL ans, sum = 0, ans_gap = 0, mid_pre = -1;
      map<LL, int>:: iterator it = mp.begin();
      for( ; it != mp.end(); ++it )
      {
            sum += ( it->second );
            if( mid_pre != -1 )
            {
                  ans_gap += ( it->first ) - mid_pre;
                  ans = mid_pre;
            }
            if( sum == q ) mid_pre = ( it->first );
            else mid_pre = -1;
      }
      if( ans_gap == 1 ) cout << ans << endl;
      else if( ans_gap > 1 ) puts( "Data not sufficient!\n" );
      else puts( "Game cheated!\n" );
      return 0;
}
/*

*/
时间: 2024-08-03 11:28:52

区间合并 --- Codeforces 558D : Gess Your Way Out ! II的相关文章

codeforces 558D Guess Your Way Out! II 规律

题目链接 题意: 给出n和q 表示有一棵深度为n的完全二叉树,叶子节点中有恰好一个点是出口 主角从根往下走,但不知道出口在哪里,但主角会获得q个提示.  像这样标号 q个提示 格式: deep [l, r] ok 表示 深度为deep 时, 出口(可能在) (一定不在)[l,r]区间 ok=1表示 是可能在 ok=0一定不在 目标: 若根据提示能找到出口则输出叶子节点下标,有多个可能的出口则输出data not sufficient,若给出的提示互相矛盾输出 Game cheatde 思路: 首

Educational Codeforces Round 72 (Rated for Div. 2)E. Sum Queries?(线段树区间合并)

https://codeforc.es/contest/1217/problem/E 建立9棵数位线段树维护区间最小值和次小值,建议用struct建树方便进行区间合并 1 #define bug(x) cout<<#x<<" is "<<x<<endl 2 #define IO std::ios::sync_with_stdio(0) 3 #include <bits/stdc++.h> 4 #define iter ::it

7620:区间合并

7620:区间合并 总时间限制: 1000ms 内存限制: 65536kB 描述 给定 n 个闭区间 [ai; bi],其中i=1,2,...,n.任意两个相邻或相交的闭区间可以合并为一个闭区间.例如,[1;2] 和 [2;3] 可以合并为 [1;3],[1;3] 和 [2;4] 可以合并为 [1;4],但是[1;2] 和 [3;4] 不可以合并. 我们的任务是判断这些区间是否可以最终合并为一个闭区间,如果可以,将这个闭区间输出,否则输出no. 输入 第一行为一个整数n,3 ≤ n ≤ 5000

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan

(树链剖分+区间合并)HYSBZ - 2243 染色

题意: 两个操作: 1.把一条树链上的所有点权值变为w. 2.查询一条树链上有多少个颜色段 分析: 一看就是区间合并,做这到题首先需要一定的区间合并基础, 不过这题合并这部分在线段树区间合并中已经算是非常的简单的了. 线段树部分没有难度. 那么难点在于,在往LCA上走的时候,我们如何进行区间合并. 本来我想着, 在向上走的时候顺便进行区间判断并且合并,但是似乎有问题. 其实,可以将两步分开,先算出区间没合并之前的颜色段数,再次进行Top,判断颜色是否相等,相等就减掉. 代码: 1 #includ

poj3667(并查集区间合并&amp;区间查询)

题目链接: http://poj.org/problem?id=3667 题意:第一行输入 n, m表示有 n 间房间(连成一排的), 接下来有 m 行输入, 对于接下来的 m 行输入: 1 x : 询问是否有长度为 x 的连号空房, 若有, 住进最左边并输出对应编号: 2 x y : 将区间 [x, x + y - 1] 的房间清空: 思路: 并查集区间合并&区间查询 下面一段题解摘自: http://www.cnblogs.com/scau20110726/archive/2013/05/0

HDU 1540 Tunnel Warfare 平衡树 / 线段树:单点更新,区间合并

Tunnel Warfare                                  Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast

HDU 3308 LCIS (线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1

HDU 2871 Memory Control(线段树&#183;区间合并&#183;Vector)

题意  模拟内存申请  有n个内存单元  有以下4种操作 Reset  将n个内存单元全部清空 New x  申请一个长度为x的连续内存块  申请成功就输出左端 Free x  将x所在的内存块空间释放  释放成功输出释放的内存始末位置 Get x  输出第x个内存块的起始位置 Reset 和 New 都是基本的区间合并知识  比较简单  Free和Get需要知道内层块的位置  所以我们在New的时候要将申请的内存块的始末位置都存起来  两个内层块不会相交  这样就能通过二分找到需要的内层块了