2015湖南省队集训DAY3——Light

本文介绍了一道编程题目,涉及到数据结构Light的解决方案。问题涉及计算两个位置间graze值,需要支持Modify和Query两种操作,并考虑历史版本的影响。题解建议使用线段树配合平衡树来解决,避免了使用k-d树导致的复杂性问题。样例输入和输出以及数据规模给出,便于理解题目要求。
摘要由CSDN通过智能技术生成

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

【数据规模与约定】

n40000,m60000,ai100000

题解:
出题人的题解真是简单(虽然题目也很简单)
“直接线段树套平衡树就可以了”
傻逼k-d树调了快俩小时,这搞腿子。
因为询问是与给定点的曼哈顿距离小于给定值的点个数,这个可以把坐标转换一下,像这样:

x=x+yy=xy

然后询问就变成一个正方形了。
代码在这:
(因为是考场代码所以有暴力的特判和一些奇怪的注释,而且不知道为什么就有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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值