HDU 5741 Helter Skelter

离线处理+扫描线。题意很容易转化:若干个矩形形成并集,询问一些点是否在并集中?

官方题解不是这样做的....那种做法效率更高,暂时还不会。我这样是4500ms G++过的,C++TLE......

区间加上某值,询问单点值,可以用树状数组。用线段树可能常数较大导致TLE。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi = acos(-1.0), eps = 1e-8;
void File()
{
    freopen("D:\\in.txt", "r", stdin);
    freopen("D:\\out.txt", "w", stdout);
}
inline int read()
{
    char c = getchar();  while (!isdigit(c)) c = getchar();
    int x = 0;
    while (isdigit(c)) { x = x * 10 + c - ‘0‘; c = getchar(); }
    return x;
}

int T, n, ps, pq, v[1010], c[2000000 + 10];
int A[2000000 + 10], sz;
struct Seg { int x, y1, y2, f; }s[2000000 + 10]; int ns;
struct Quary { int x, y, id; }q[500000 + 10]; int nq;
int ans[500000 + 10];

int lowbit(int x) { return x&(-x); }
void add(int p, int val) { while (p <= sz) c[p] = c[p] + val, p = p + lowbit(p); }
int sum(int p) { int r = 0; while (p > 0) r = r + c[p], p = p - lowbit(p); return r; }
void update(int L, int R, int val) { add(L, val); add(R + 1, -val); }

void AddSeg(int l, int r, int L, int R)
{
    s[ns].x = l, s[ns].y1 = L, s[ns].y2 = R, s[ns].f = 1, ns++;
    s[ns].x = r, s[ns].y1 = L, s[ns].y2 = R, s[ns].f = -1, ns++;
    A[sz++] = L, A[sz++] = R;
}

bool cmp(Seg a, Seg b) { if (a.x == b.x) return a.f > b.f; return a.x < b.x; }
bool cmp2(Quary a, Quary b) { return a.x < b.x; }

void get()
{
    int x = lower_bound(A, A + sz, q[pq].y) - A; x++;
    if (sum(x) > 0) ans[q[pq].id] = 1; else ans[q[pq].id] = 0; pq++;
}

void insert()
{
    int L = lower_bound(A, A + sz, s[ps].y1) - A; L++;
    int R = lower_bound(A, A + sz, s[ps].y2) - A; R++;
    update(L, R, s[ps].f); ps++;
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d%d", &n, &nq);
        for (int i = 1; i <= n; i++) scanf("%d", &v[i]);

        ns = 0; sz = 0;
        for (int i = 1; i <= n; i++)
        {
            int l = 0, r = 0, L = 0, R = 0, w = 0, b = 0;
            if (i & 1) AddSeg(0, v[i], 0, 0); else AddSeg(0, 0, 0, v[i]);
            for (int j = i + 1; j <= n; j++)
            {
                l = r = w; L = R = b;
                if (i & 1) r = r + v[i]; else R = R + v[i];
                if (j & 1) r = r + v[j]; else R = R + v[j];
                AddSeg(l, r, L, R);
                if (j & 1) w = w + v[j]; else b = b + v[j];
            }
        }

        for (int i = 0; i < nq; i++)
        {
            scanf("%d%d", &q[i].x, &q[i].y); q[i].id = i;
            A[sz++] = q[i].y;
        }

        sort(s, s + ns, cmp); sort(q, q + nq, cmp2);
        sort(A, A + sz); sz = unique(A, A + sz) - A;

        ps = 0, pq = 0; memset(c, 0, sizeof c);
        while (pq < nq)
        {
            if (ps == ns) get();
            else
            {
                if (s[ps].x < q[pq].x) insert();
                else if (s[ps].x > q[pq].x) get();
                else { if (s[ps].f == 1) insert(); else get(); }
            }
        }
        for (int i = 0; i < nq; i++) printf("%d", ans[i]); printf("\n");
    }
    return 0;
}
时间: 2024-10-12 03:41:12

HDU 5741 Helter Skelter的相关文章

hdu 5741 Helter Skelter(扫描线)

题目链接:hdu 5741 Helter Skelter 题意: 给定一个二进制的字符串,有 M次询问 问是否存在含有 a个 0 ,b个 1的区间 题解: 我们可以n2处理出每个区间,然后我们可以发现每个区间是一个矩形. 现在问题就转换成了有多少个点在这些矩形内. 然后就可以离散化后扫描线一下. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 5 con

HDU - 5741 Helter Skelter 扫描线 + 树状数组

HDU - 5741 我们枚举段的起点和终点, 那么每一种情况0的范围是[lx, rx], 1的出现范围是[ly, ry], 可以在二维平面上用矩形表示. 然后问题就变成了询问点有没有被至少一个矩形覆盖, 扫描线 + 树状数组就可以了. #pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL long long #define LD long double #define ull un

HDU 5741 Helter Skelter(构造法)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5741 [题目大意] 一个01相间的串,以0开头,给出的序列每个数字表示连续的0的个数或者1的个数,现在有m个询问,求0的个数为a且1的个数为b的串是否存在. [题解] 我们发现形如11001这样子以1为开头结尾的串是包含1001这样子的串的,同理以0为开头结尾的串也是包含了一些开头结尾数字相同的子串. 可以发现,当0的个数固定,1的个数是数轴上的一个区间,而且在0的个数相差1时,必定可以取到相同

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

[hdu 2102]bfs+注意INF

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2102 感觉这个题非常水,结果一直WA,最后发现居然是0x3f3f3f3f不够大导致的--把INF改成INF+INF就过了. #include<bits/stdc++.h> using namespace std; bool vis[2][15][15]; char s[2][15][15]; const int INF=0x3f3f3f3f; const int fx[]={0,0,1,-1};

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是

HDU 5917 Instability ramsey定理

http://acm.hdu.edu.cn/showproblem.php?pid=5917 即世界上任意6个人中,总有3个人相互认识,或互相皆不认识. 所以子集 >= 6的一定是合法的. 然后总的子集数目是2^n,减去不合法的,暴力枚举即可. 选了1个肯定不合法,2个也是,3个的话C(n, 3)枚举判断,C(n, 4), C(n, 5) #include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using name