ural 1707. Hypnotoad's Secret(线段树)

题目链接:ural 1707. Hypnotoad‘s Secret

题目大意:给定N和M,然后N组s0, t0, Δs, Δt, k,每组可以计算出k个星星的坐标;M组a0, b0, c0, d0, Δa, Δb, Δc,

Δd, q,每组要求算出q个矩形,判断矩形内是否包含星星,对于q≥20的情况要根据公式计算一个值即可。

解题思路:计算出所有的星星坐标和矩阵,这个每的说了,将矩阵差分成两点,通过计算出每个点左下角有多少个星

星,然后用容斥计算出矩阵内是否有点。这个属于线段树的一个应用。

#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;
typedef long long ll;

const ll mod = 200904040963LL;
const int maxn = 300000;

#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)|1)
int lc[maxn << 2], rc[maxn << 2], s[maxn << 2];

inline void pushup(int u) {
    s[u] = s[lson(u)] + s[rson(u)];
}

void build (int u, int l, int r) {
    lc[u] = l;
    rc[u] = r;
    s[u] = 0;

    if (l == r)
        return;

    int mid = (l + r) / 2;
    build(lson(u), l, mid);
    build(rson(u), mid + 1, r);
    pushup(u);
}

void modify(int u, int x) {
    if (lc[u] == x && x == rc[u]) {
        s[u] += 1;
        return;
    }

    int mid = (lc[u] + rc[u]) / 2;
    if (x <= mid)
        modify(lson(u), x);
    else
        modify(rson(u), x);
    pushup(u);
}

int query(int u, int l, int r) {
    if (l <= lc[u] && rc[u] <= r)
        return s[u];

    int mid = (lc[u] + rc[u]) / 2, ret = 0;
    if (l <= mid)
        ret += query(lson(u), l, r);
    if (r > mid)
        ret += query(rson(u), l, r);
    return ret;
}

struct point {
    int t,  x, y;
    point (int x = 0, int y = 0, int t = 0) {
        set(x, y);
        this->t = t;
    }
    void set (int x, int y) {
        this->x = x;
        this->y = y;
    }
    friend bool operator < (const point& a, const point& b) {
        if (a.x != b.x)
            return a.x < b.x;
        if (a.y != b.y)
            return a.y < b.y;
        return a.t < b.t;
    }
};

struct state {
    point a, b;
    state (point a, point b) {
        this->a = a;
        this->b = b;
    }
};

int N, M, P;
ll T[350];
vector<int> pos, tmp, cnt;
vector<point> vec;
vector<state> que;
map<point, int> G;

inline void add_point (ll x, ll y, int k) {
    vec.push_back(point(x, y, k));
    tmp.push_back(y);
}

inline void add_state (int a, int b, int c, int d) {
    add_point(a - 1, b - 1, 1);
    add_point(c, d, 1);

    int u = vec.size();
    que.push_back(state(vec[u-2], vec[u-1]));

    add_point(a - 1, d, 1);
    add_point(c, b - 1, 1);
}

inline int find (int a) {
    return lower_bound(pos.begin(), pos.end(), a) - pos.begin();
}

void init () {
    G.clear();
    cnt.clear();
    vec.clear();
    que.clear();
    pos.clear();
    tmp.clear();

    int a, b, c, d, aa, bb, cc, dd, k;

    for (int i = 0; i < M; i++) {
        scanf("%d%d%d%d%d", &a, &b, &aa, &bb, &k);
        a = (a + N) % N; b = (b + N) % N;
        for (int j = 0; j < k; j++) {
            add_point(a, b, 0);
            a = (a + aa + N) % N;
            b = (b + bb + N) % N;
        }
    }

    scanf("%d", &P);
    for (int i = 0; i < P; i++) {
        scanf("%d%d%d%d", &a, &b, &c, &d);
        scanf("%d%d%d%d%d", &aa, &bb, &cc, &dd, &k);
        a = (a + N) % N; b = (b + N) % N;
        c = (c + N) % N; d = (d + N) % N;

        cnt.push_back(k);
        for (int j = 0; j < k; j++) {
            add_state(min(a, b), min(c, d), max(a, b), max(c, d));

            a = (a + aa + N) % N; b = (b + bb + N) % N;
            c = (c + cc + N) % N; d = (d + dd + N) % N;
        }
    }

    sort(vec.begin(), vec.end());
    sort(tmp.begin(), tmp.end());
    pos.push_back(tmp[0]);
    for (int i = 1; i < tmp.size(); i++) {
        if (tmp[i] != tmp[i-1])
            pos.push_back(tmp[i]);
    }
    build(1, 0, pos.size());
}

inline int judge (state u) {
    return G[u.b] + G[u.a] - G[point(u.b.x, u.a.y, 1)] - G[point(u.a.x, u.b.y, 1)];
}

void solve () {
    for (int i = 0; i < vec.size(); i++) {
        if (vec[i].t)
            G[vec[i]] = query(1, 0, find(vec[i].y));
        else
            modify(1, find(vec[i].y));
    }

    int mv = 0;
    for (int i = 0; i < cnt.size(); i++) {
        if (cnt[i] > 20) {
            ll ret = 0;
            for (int j = 0; j < cnt[i]; j++)
                ret = (ret + (judge(que[mv + j]) > 0 ? 1 : 0) * T[j]) % mod;
            printf("%lld", ret);
        } else {
            for (int j = 0; j < cnt[i]; j++)
                printf("%d", judge(que[mv + j]) > 0 ? 1 : 0);
        }

        mv += cnt[i];
        printf("\n");
    }
}

int main () {

    T[0] = 1;
    for (int i = 1; i <= 345; i++)
        T[i] = T[i-1] * 7 % mod;

    while (scanf("%d%d", &N, &M) == 2) {
        init();
        solve();
    }
    return 0;
}

ural 1707. Hypnotoad's Secret(线段树)

时间: 2024-10-08 10:28:09

ural 1707. Hypnotoad's Secret(线段树)的相关文章

URAL 1707. Hypnotoad&#39;s Secret(树状数组)

URAL 1707. Hypnotoad's Secret 题目链接 题意:这题设置的恶心不能多说,构造点和矩形,大概就是问每个矩形里面是否包含点 思路:树状数组,把点排序,按y轴,在按x轴,在按询问,这样每次遇到一个点就在相应的扫描线上加,遇到查询就询问出左边到这个点位置的,就能预处理出每个点左下角包含的点的个数,然后每个矩形再利用容斥原理去搞一下即可 代码: #include <cstdio> #include <cstring> #include <algorithm&

URAL 1707. Hypnotoad&amp;#39;s Secret(树阵)

URAL 1707. Hypnotoad's Secret space=1&num=1707" target="_blank" style="">题目链接 题意:这题设置的恶心不能多说.构造点和矩形.大概就是问每一个矩形里面是否包括点 思路:树状数组.把点排序,按y轴,在按x轴.在按询问,这样每次遇到一个点就在对应的扫描线上加.遇到查询就询问出左边到这个点位置的,就能预处理出每一个点左下角包括的点的个数,然后每一个矩形再利用容斥原理去搞一下就

ural 1019 Line Painting(线段树)

题目链接:ural 1019 Line Painting 题目大意:一个0~1e9的区间,初始都是白的,现进行N次操作,每次将一段区间图上一中颜色.最后问说连续最长的白色区间. 解题思路:线段树区间合并,每个节点即维护一个区间,很经典.注意坐标需要离散化,但是还是要将0和1e9放进去. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn

URAL 1989 Subpalindromes(回文串 线段树 多项式hash)

1989. Subpalindromes Time limit: 0.5 second Memory limit: 64 MB You have a string and queries of two types: replace i'th character of the string by character a; check if substring sj...sk is a palindrome. Input The first line contains a string consis

URAL 1019. Line Painting 线段树 区间合并 离散化

题目来源:URAL 1019. Line Painting 题意:求最长的一段全部为白色的区间 思路:线段树成段更新 区间合并 离散化 这里对应的是一段区间 所以每次不是m+1 而是 l m 和 m r 了 另外我加上了0 和 10^9 这两个点 每一段区间(l, r)我记录的是l和r之间有多少条线段 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const

URAL 1890 . Money out of Thin Air (dfs序hash + 线段树)

题目链接: URAL 1890 . Money out of Thin Air 题目描述: 给出一个公司里面上司和下级的附属关系,还有每一个人的工资,然后有两种询问: 1:employee x y z ,如果编号为x的员工如果工资小于y,就给他加薪z. 2:department x y z ,如果编号为x的员工所管辖的范围内(包括自己),所有员工的工资平均数小于y,给该范围加薪z. 问q次操作后这个公司内每个员工的工资为多少? 解题思路: 根据上司和下级的附属关系,可以先建一个有向图,然后对有向

URAL 2014 Zhenya moves from parents 线段树

线段树,前缀和最小 Zhenya moves from parents Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description Zhenya moved from his parents' home to study in other city. He didn't take any cash with him, he only took his f

数据结构---线段树

线段树 转载请注明出处,谢谢!http://blog.csdn.net/metalseed/article/details/8039326  持续更新中···   一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树

(转载)线段树模板(来自胡浩大牛)

http://www.notonlysuccess.com/(今天看二叉树,想回来看看,发现大牛博客进不去...) 如果要学,就要好好学.我copy的,如有错,请看http://www.cnblogs.com/Mu-Tou/archive/2011/08/11/2134427.html [完全版]线段树 很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章了,觉得当时的代码风格实在是太丑了,很多线段树的初学者