HDU 4866 多校1 主席树+扫描线

终于是解决了这个题目了

不过不知道下一次碰到主席树到底做不做的出来,这个东西稍微难一点就不一定能做得出

离散化+扫描线式的建树,所以对于某个坐标二分找到对应的那颗主席树,即搜索出结果即可(因为是扫描线式的建树,找到对应的树之后,就知道该点上面的线段有多少条了)

其他就是普通主席树的操作了

主席树里面维护两个东西,一个就是普通的那种在该区间的节点数目,另外就是权值

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL __int64
using namespace std;
const int N =200010;
const int maxn=N*100;
int n,m,x,p,tot;
int t[N],T[N];
int c1[maxn],lson[maxn],rson[maxn];
LL c2[maxn];
struct node2
{
    int h,id;
    bool operator < (const node2 rhs) const
    {
        return h<rhs.h;
    }
}y[N];
struct node
{
    int d,h,id;
    bool operator < (const node& rhs)const{
        if (d!=rhs.d) return d<rhs.d;
        else return h>rhs.h;
    }
}seg[N];
int build(int l,int r)
{
    int rt=++tot;
    c1[rt]=c2[rt]=0;
    if (l>=r) return rt;
    int mid=(l+r)>>1;
    lson[rt]=build(l,mid);
    rson[rt]=build(mid+1,r);
    return rt;
}
int inserts(int rt,int pos,int v1,LL v2)
{
    int newrt=++tot;
    int tmp=newrt;
    c1[newrt]=c1[rt]+v1;
    c2[newrt]=c2[rt]+v2;
    int l=1,r=n;
    while (l<r)
    {
        int mid=(l+r)>>1;
        if (pos<=mid){
            lson[newrt]=++tot;
            rson[newrt]=rson[rt];
            newrt=lson[newrt];
            rt=lson[rt];
            r=mid;
        }
        else{
            rson[newrt]=++tot;
            lson[newrt]=lson[rt];
            newrt=rson[newrt];
            rt=rson[rt];
            l=mid+1;
        }
        c1[newrt]=c1[rt]+v1;
        c2[newrt]=c2[rt]+v2;
    }
    return tmp;
}
LL query(int rt,int pos)
{
    LL ret=0;
    int l=1,r=n;
    while (l<r)
    {
        int mid=(l+r)>>1;
        if (c1[lson[rt]]>=pos){
            r=mid;
            rt=lson[rt];
        }
        else
        {
            pos-=c1[lson[rt]];
            ret+=c2[lson[rt]];
            rt=rson[rt];
            l=mid+1;
        }
    }
    return c2[rt]+ret;
}
int main()
{
    int loc,a,b,c;
    while (scanf("%d%d%d%d",&n,&m,&x,&p)!=EOF)
    {
        int cnt=0;
        tot=0;
        for (int i=1;i<=n;i++){
            scanf("%d%d%d",&a,&b,&c);
            y[i].h=c;
            y[i].id=i;
            seg[++cnt]=(node){a,c,i};
            seg[++cnt]=(node){b,-c,i};
        }
        sort(seg+1,seg+1+cnt);
        sort(y+1,y+1+n);
        for (int i=1;i<=n;i++){
            t[y[i].id]=i;
        }
        T[0]=build(1,n);
        for (int i=1;i<=cnt;i++){
            if (seg[i].h>=0)
                T[i]=inserts(T[i-1],t[seg[i].id],1,seg[i].h);
            else
                T[i]=inserts(T[i-1],t[seg[i].id],-1,seg[i].h);
        }
        LL pre=1;
        while (m--)
        {
            scanf("%d%d%d%d",&loc,&a,&b,&c);
            int K;
            K=(a%c*pre%c+b)%c;
            if (K==0){
                puts("0");
                pre=0;
                continue;
            }
            int id;
            int l=1,r=cnt+1;
            while (l<r)
            {
                int mid=(l+r)>>1;
                if (seg[mid].d<loc || (seg[mid].d==loc && seg[mid].h>=0)){
                    id=mid;
                    l=mid+1;
                }
                else{
                    r=mid;
                }
            }
            LL ans=query(T[id],K);
            if (pre>p) ans*=2;
            pre=ans;
            printf("%I64d\n",ans);
        }
    }
    return 0;
}

  

HDU 4866 多校1 主席树+扫描线

时间: 2024-07-28 15:30:16

HDU 4866 多校1 主席树+扫描线的相关文章

HDU 4866 Shooting 题解:主席树

这题的主要的坑点就是他给你的射击目标有重合的部分,如果你向这些重合的部分射击的话要考虑两种情况: 射击目标数量 ≥ 重合数量 : 全加上 射击目标数量 ≤ 重合数量 : 只加距离*射击目标数量 然而这题的内存还是很良心的,总体比较水吧. 主要做法是按照横坐标1~x建立主席树,每棵主席树维护l,r区间的设计目标数量,以及这些数量如果全部被射击获得的分数,这些在建树的时候是很好维护的. 然后对这些线段的处理要用扫描线的思想,就(左端点)建立一个(+1)的入点,(右端点+1)的位置建立一个(-1)的出

HDU 3642 Get The Treasury 线段树+扫描线

反向标记是错的,要对矩形进行拆分 #include <cstdio> #include <algorithm> #include <cstring> #include <vector> typedef long long LL; using namespace std; #define lson rt << 1,l,mid #define rson rt << 1 | 1,mid + 1,r const int maxn = 5e4

HDU 1264 Counting Squares (线段树-扫描线-矩形面积并)

Problem A : Counting Squares From:HDU, 1264 Problem Description Your input is a series of rectangles, one per line. Each rectangle is specified as two points(X,Y) that specify the opposite corners of a rectangle. All coordinates will be integers in t

hdu 1255 覆盖的面积(线段树&amp;扫描线&amp;重复面积)

覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3375    Accepted Submission(s): 1645 Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数

hdu 1255 覆盖的面积 线段树扫描线求重叠面积

稀里糊涂打完了没想到1A了,心情还是很舒畅的,c和c++的四舍五入还是四舍六入遇积进位遇偶舍,我感觉很混乱啊,这道题我输出的答案是7.62,也就是遇偶舍了,可是我就手动处理一下进位问题,发现0.005 系统自动进位0.01了,尼玛啊,我一下子就混乱了,不是遇偶舍么,0也是偶数啊,怎么就进位了呢.最后我就不手动处理进位问题了,直接0.2lf%,虽然我输出的结果是7.62,但是提交也过了 这道题和poj1151,hdu1542差不多,扫描线详细讲解http://blog.csdn.net/young

hdu 4348 To the moon(主席树区间操作)

题目链接:hdu 4348 To the moon 题意: 给你n个数,有m个操作. 1.给区间[l,r]的所有数+d,并且时间戳+1 2.询问当前时间戳的区间和. 3.询问过去时间戳t的区间和. 4.退回到时间戳t. 题解: 直接上主席树. 不过区间操作的时候push_down空间似乎不是那么够用. 所有把push_down这个操作去掉. 用一个标记记录当前这个区间的累加. 询问的时候就将这个累加传下去.(具体看代码) 最后还有退回状态t的时候可以把cnt=root[t+1], 因为后面的内存

HDU 4417 Super Mario(主席树求区间内的区间查询+离散化)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5101    Accepted Submission(s): 2339 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping abilit

POJ 2104&amp;HDU 2665 Kth number(主席树入门+离散化)

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 50247   Accepted: 17101 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

hdu 4348 To the moon (主席树)

hdu 4348 题意: 一个长度为n的数组,4种操作 : (1)C l r d:区间[l,r]中的数都加1,同时当前的时间戳加1 . (2)Q l r:查询当前时间戳区间[l,r]中所有数的和 . (3)H l r t:查询时间戳t区间[l,r]的和 . (4)B t:将当前时间戳置为t . 所有操作均合法 . 解法: 很明显是一道主席树的题 . 对于每一次区间加法都新建节点建一棵线段树,加个懒惰标记就行了,查询的话直接线段树区间求和 . 不过感觉这一题就是为可持续化数据结构写的,特别是时间戳