2015湖南省队集训DAY3——Light

Light

【问题描述】

“若是万一琪露诺(俗称 rhl)进行攻击,什么都好,冷静地回答她的问题来吸引

对方表现出兴趣的话,那就慢慢地反问。在她考虑答案的时候,趁机逃吧。就算是很简

问题,她一定也答不上来。” ——《上古之魔书》

天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列 a[i],远

魔书上记载到:2 个位置的 graze 值为两者位置差与数值差的和:

graze(x,y)=|x-y|+|a[x]-a[y]|。

要想破解天罚,就必须支持 2种操作(k 都是正整数):

Modify x k:将第 x个数的值修改为k。

Query x k:询问有几个 i满足graze(x,i)<=k。

由于从前的天罚被圣王lmc破解了,所以rhl改进了她的法术,询问不仅要考虑当

列,还要考虑任意历史版本,即统计任意位置上出现过的任意数值与当前的a[x]的 graz

<=k的对数。(某位置多次修改为同样的数值,按多次统计)

【输入格式】

第1行两个整数 n,q。分别表示数列长度和操作数。

第2行 n个正整数,代表初始数列。

第3~q+2 行每行一个操作。

【输出格式】

对于每次询问操作,输出一个非负整数表示答案。

【样例输入】

3 5

2 4 3

Query 2 2

Modify 1 3

Query 2 2

Modify 1 2

Query 1 1

【样例输出】

2

3

3

【数据规模与约定】

n≤40000,m≤60000,ai≤100000

题解:

出题人的题解真是简单(虽然题目也很简单)

“直接线段树套平衡树就可以了”

傻逼k-d树调了快俩小时,这搞腿子。

因为询问是与给定点的曼哈顿距离小于给定值的点个数,这个可以把坐标转换一下,像这样:

x′=x+yy′=x?y

然后询问就变成一个正方形了。

代码在这:

(因为是考场代码所以有暴力的特判和一些奇怪的注释,而且不知道为什么就有6.6k了)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef double db;

const int inf=300005;

int getint()
{
    int f=1,g=0;char c=getchar();
    while(c<‘0‘ || c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c<=‘9‘ && c>=‘0‘)g=(g<<3)+(g<<1)+c-‘0‘,c=getchar();
    return f*g;
}

int n;
int q;

namespace brute_force{

    const int maxn=200005;

    vector<int> a[maxn];
    int b[maxn];

    bool check()
    {
        return q<=99;
    }

    char opt[20];

    void solve()
    {
        for(int i=1;i<=n;i++)
        {
            a[i].push_back(getint());
            b[i]=a[i][0];
        }

        int x,y;

        for(int i=1;i<=q;i++)
        {
            scanf("%s",opt);
            if(opt[0]==‘M‘)
            {
                x=getint();
                y=getint();
                a[x].push_back(y);
                b[x]=y;
            }
            if(opt[0]==‘Q‘)
            {
                x=getint();
                y=getint();
                int cnt=0;
                for(int j=1;j<=n;j++)
                {
                    for(int l=0;l<a[j].size();l++)
                    {
                        if(abs(x-j)+abs(b[x]-a[j][l])<=y)
                        {
                            cnt++;
                        }
                    }
                }
                printf("%d\n",cnt);
            }
        }
    }

}

namespace another_brute_force{

    const int maxn=160005;

    struct node{
        int d[2];
        int min[2];
        int max[2];
        int cnt;
        int size;
        int l,r;

        int& operator [] (const unsigned int& num)
        {
            return d[num];
        }       

    };  

    node t[maxn];
    node p[maxn];

    int dim;
    int tot;

    #define ls t[x].l
    #define rs t[x].r

    #define lc t[t[x].l]
    #define rc t[t[x].r]

    #define mid (l+r>>1)

    bool cmp (const node& n1,const node& n2)
    {
        return n1.d[dim]<n2.d[dim];
    }

    struct kd_tree
    {
        node T;
        int root;

        void update(int x)
        {
            t[x].size=t[x].cnt;
            t[x].min[0]=t[x].max[0]=t[x][0];
            t[x].min[1]=t[x].max[1]=t[x][1];
            for(int i=0;i<2;i++)
            {
                if(ls)
                {
                    t[x].max[i]=max(t[x].max[i],lc.max[i]);
                    t[x].min[i]=min(t[x].min[i],lc.min[i]);
                }
                if(rs)
                {
                    t[x].max[i]=max(t[x].max[i],rc.max[i]);
                    t[x].min[i]=min(t[x].min[i],rc.min[i]);
                }
            }
            if(ls)t[x].size+=lc.size;
            if(rs)t[x].size+=rc.size;
        }
        /**/
        void build(int &x,int l,int r,int now)
        {
            if(l>r)return;
            dim=now;
            nth_element(p+l,p+mid,p+r,cmp);

            x=mid;
            t[x].cnt=1;
            t[x].size=1;
            for(int i=0;i<2;i++)
            {
                t[x][i]=t[x].min[i]=t[x].max[i]=p[x][i];
            }
            build(ls,l,mid-1,now^1);
            build(rs,mid+1,r,now^1);
            update(x);
        }
        void insert(int& x,int now)
        {
            if(!x)
            {
                x=++tot;
                t[x]=T;
                return;
            }
            if(T[0]==t[x][0] && T[1]==t[x][1])
            {
                t[x].cnt++;
                t[x].size++;
                return;
            }
            if(T[now]>t[x][now])
            {
                insert(rs,now^1);
                update(x);
            }
            else
            {
                insert(ls,now^1);
                update(x);
            }
        }

        int k;
        int The_Answer;
        /*
        bool check(int x)
        {
            int left=T[0]-k;
            int right=T[0]+k;
            int up=T[1]+k;
            int down=T[1]-k;
            if(down>t[x].max[1] || up<t[x].min[1] || left>t[x].max[0] || right<t[x].min[0])
            return false;
            return true;
        }

        int get(int x)
        {
            int left=T[0]-k;left=max(0,t[x].max[0]-left);
            int right=T[0]+k;right=max(0,right-t[x].min[0]);
            int up=T[1]+k;up=max(0,up-t[x].min[1]);
            int down=T[1]-k;down=max(0,t[x].max[1]-down);
            return min(min(left,right),min(up,down));
        }

        void query(int x)
        {
            if(!x)return;
            if(max(abs(t[x].min[0]-T[0])+abs(t[x].min[1]-T[1]),abs(t[x].max[0]-T[0])+abs(t[x].max[1]-T[1]))<=k
            && max(abs(t[x].min[0]-T[0])+abs(t[x].max[1]-T[1]),abs(t[x].min[1]-T[1])+abs(t[x].max[0]-T[0]))<=k)
            {
                The_Answer+=t[x].size;
                return;
            }
            /*
            if(min(abs(t[x].min[0]-T[0])+abs(t[x].min[1]-T[1]),abs(t[x].max[0]-T[0])+abs(t[x].max[1]-T[1]))>k
            && min(abs(t[x].min[0]-T[0])+abs(t[x].max[1]-T[1]),abs(t[x].min[1]-T[1])+abs(t[x].max[0]-T[0]))>k
            &&(t[x].min[0]>T[0] || t[x].max[0]<T[0] || t[x].min[1]<T[1] || t[x].max[1]>T[1]))
            *
            if(!check(x))
            {
                return;
            }

            if(abs(t[x][0]-T[0])+abs(t[x][1]-T[1])<=k)
            {
                The_Answer+=t[x].cnt;
            }
/*
int tl=min( min(abs(lc.min[0]-T[0])+abs(lc.min[1]-T[1]),abs(lc.max[0]-T[0])+abs(lc.max[1]-T[1])),
            min(abs(lc.min[0]-T[0])+abs(lc.max[1]-T[1]),abs(lc.max[0]-T[0])+abs(lc.min[1]-T[1])));

int tr=min( min(abs(rc.min[0]-T[0])+abs(rc.min[1]-T[1]),abs(rc.max[0]-T[0])+abs(rc.max[1]-T[1])),
            min(abs(rc.min[0]-T[0])+abs(rc.max[1]-T[1]),abs(rc.max[0]-T[0])+abs(rc.min[1]-T[1])));
*
            int tl=get(ls);
            int tr=get(rs);
            if(tl<=tr)
            {
                if(tl<=k)query(ls);
                if(tr<=k)query(rs);
            }
            else
            {
                if(tr<=k)query(rs);
                if(tl<=k)query(ls);
            }
        }
        */

        node T1,T2;

        void query(int x)
        {
            if(!x)return;
            if(t[x].max[0]<T1[0] || t[x].min[0]>T2[0] || t[x].max[1]<T1[1] || t[x].min[1]>T2[1])return;
            if(t[x].max[0]<=T2[0] && t[x].min[0]>=T1[0] && t[x].max[1]<=T2[1] && t[x].min[1]>=T1[1])
            {
                The_Answer+=t[x].size;
                return;
            }
            if(t[x][0]>=T1[0] && t[x][0]<=T2[0] && t[x][1]>=T1[1] && t[x][1]<=T2[1])
            {
                The_Answer+=t[x].cnt;
            }

            int tl=min(min(abs(T1[0]-lc.max[0]),abs(T2[0]-lc.min[0])),min(T1[1]-lc.max[1],T2[1]-lc.min[1]));
            int tr=min(min(abs(T1[0]-rc.max[0]),abs(T2[0]-rc.min[0])),min(T1[1]-rc.max[1],T2[1]-rc.min[1]));

            if(tl<=tr)
            {
                if(tl<=k)query(ls);
                if(tr<=k)query(rs);
            }
            else
            {
                if(tr<=k)query(rs);
                if(tl<=k)query(ls);
            }
        }

        void ins(int x,int y)
        {
            T[0]=T.min[0]=T.max[0]=x;
            T[1]=T.min[1]=T.max[1]=y;
            T.size=T.cnt=1;
            T.l=T.r=0;
            insert(root,0);
        }
        int que(int x,int y,int kk)
        {
            T1[0]=max(-inf,x-kk);
            T2[0]=min(inf,x+kk);
            T1[1]=max(-inf,y-kk);
            T2[1]=min(inf,y+kk);
            k=kk;The_Answer=0;
            query(root);
            return The_Answer;
        }
    }kdtree;

    int b[maxn];

    char opt[20];

    void solve()
    {
        kdtree.The_Answer=0;
        for(int i=1;i<=n;i++)
        {
            b[i]=getint();
            //kdtree.ins(i+b[i],i-b[i]);
            p[i][0]=i+b[i];
            p[i][1]=i-b[i];
        }
        kdtree.build(kdtree.root,1,n,0);
        tot=n;
        int x,y;
        for(int i=1;i<=q;i++)
        {
            scanf("%s",opt);
            if(i==10000)
            {
                i++;
                i--;
            }
            if(opt[0]==‘Q‘)
            {
                x=getint();
                y=getint();
                printf("%d\n",kdtree.que(x+b[x],x-b[x],y));
            }
            else
            {
                x=getint();
                y=getint();
                b[x]=y;
                kdtree.ins(x+b[x],x-b[x]);
            }
        }
    }
}
//expected score 100
int main()
{
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);

    n=getint();
    q=getint();
    /**/
    if(brute_force::check())
    {
        brute_force::solve();
    }
    else
    /**/
    {
        another_brute_force::solve();
    }

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-26 16:58:28

2015湖南省队集训DAY3——Light的相关文章

2015湖南省队集训DAY6——B题(BZOJ4179)

题面挺扯的,我就直接说人话算了. 题目大意:给你若干个病毒串,问你能不能构造出长度大于n的字符串使其中不出现任何一个字符串. 多组数据,总文件大小小于1M 题解: 联动:BZOJ2938 基本是原题,稍作了改动. 考虑ac自动机. 所求即为ac自动机中是否存在长度大于等于l的路径 先将所有的串插进去,然后构造失配指针. 显然的,插入后的末端节点肯定是不能经过的. 但仅这样显然是不可以的,我们考虑在匹配时,如果失配指针指向的节点是danger节点,那么这个节点也是不能经过的(显然). 所以考虑ac

省队集训Day3 light

[问题描述] “若是万一琪露诺(俗称 rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她.对方表现出兴趣的话,那就慢慢地反问.在她考虑答案的时候,趁机逃吧.就算是很简单的问题,她一定也答不上来.” ——<上古之魔书> 天空中出现了许多的北极光,这些北极光组成了一个长度为 n 的正整数数列 a[i],远古之魔书上记载到:2 个位置的 graze 值为两者位置差与数值差的和: graze(x,y)=|x-y|+|a[x]-a[y]|. 要想破解天罚,就必须支持 2 种操作(k 都是正整数):

湖南省队集训 -- 1

不知道为什么今天状态 大 好 可能是暴力分比较简单吧,来认真写一下总结 开局睡了1h-- 然后考虑a题,发现特殊性:因为最后的和一定是10^n的,最后两个数一定是后面一段全是0,前面一段两个数的和是⑨,0和⑨中间夹一对和为10 然后脑补正解不能,暴力枚举一下好像可以,就是判断是在不好写 然后考虑b题,看N^2算法,脑玩了一下发现距离是不会变得,如果钦定了一个点建站第1~n-1个点产生的权值是不会变得,最后一个点的距离也变不了,唯一得变量需求要乘距离,然后把剩下的不变量加起来,这就是个kx+b的形

bzoj4171 or 省队集训day3 chess: Rhl的游戏

[题目描述] RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色.每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子),黑变白,白变黑. RHL希望把所有格子都变成白色的.不幸的是,有一些格子坏掉了,无法被按下.这时,它可以完成游戏吗? [输入格式] 第一行一个整数T,表示T组数据. 每组数据开始于三个整数n,m,k,分别表示格子的高度和宽度.坏掉格子的个数.接下来的n行,每行一个长度m

FJ省队集训DAY3 T1

思路:我们考虑如果取掉一个部分,那么能影响到最优解的只有离它最近的那两个部分. 因此我们考虑堆维护最小的部分,离散化离散掉区间,然后用线段树维护区间有没有雪,最后用平衡树在线段的左右端点上面维护最小的id 我讲的貌似不是很清楚.. 还有,蜜汁80分,打死也改不出来.. 1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<cstring> 5 #include<algo

FJ省队集训DAY3 T2

思路:如果一个DAG要的路径上只要一条边去切掉,那么要怎么求?很容易就想到最小割,但是如果直接做最小割会走出重复的部分,那我们就这样:反向边设为inf,这样最小割的时候就不会割到了,判断无解我们直接用tarjan 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define ll long

省队集训 Day3 陈姚班

[题目大意] 给一张网格图,上往下有流量限制,下往上没有,左往右有流量限制. $n * m \leq 2.5 * 10^6$ [题解] 考场直接上最大流,50分.竟然傻逼没看出狼抓兔子. 平面图转对偶图,其中没有流量限制(inf)不用转,然后直接在DAG上分层dp即可. 复杂度$O(nm)$,但是这样过不去被卡常了. 出题人的做法是先处理出每层初始的那个随机数,然后每层往下直接做,这样因为是一维数组,所以寻址方便,不会被卡常. 我的做法是动态开数组(用new),然后比较两维大小来分配第一维给谁,

省队集训 Day3 吴清华

[题目大意] 给网格图,共有$n * n$个关键节点,横向.纵向距离均为$d$,那么网格总长度和宽度均为$(n+1) * d + 1$,最外围一圈除了四角是终止节点.要求每个关键节点都要通过线连向终止节点,每个点只能连一条线,线不能相交,且只能连在网格的边上. 求最短布线距离.提交答案题. [题解] 前面3个点(60分)可以跑费用流,这是一个经典拆点费用流模型,大概并行跑个15min也就出来了. 后面2个点据说用原始对偶跑会快很多,ditoly后两个点就跑了36分. orz ditoly

省队集训 Day3 杨北大

[题目大意] 给出平面上$n$个点$(x_i, y_i)$,请选择一个不在这$n$个点之内的点$(X, Y)$,定义$(X, Y)$的价值为往上下左右四个方向射出去直线,经过$n$个点中的数量的最小值. Task 1: 求价值最大的点 Task 2: 求价值最大的点的个数 保证Task 1和Task 2各占50pts. 对于30%的数据,$n \leq 200$: 对于60%的数据,$n \leq 5000$: 对于100%的数据,$n \leq 300000$. 每档数据中,50%保证$1 \