码迷,mamicode.com
首页 > 其他好文 > 详细

2019CCPC网络选拔赛 array(权值线段树)

时间:2019-09-01 01:20:00      阅读:62      评论:0      收藏:0      [点我收藏+]

标签:const   void   处理   数组下标   build   超过   bit   return   内存   

2019CCPC网络选拔赛1002 HDU6703

 

题目大意:

T个样例。给你一个长度为n的数组a,1≤a[i]≤n,a[i]各不相同。m个操作。ans初始为0。有两种操作:

操作1:给你t1。pos=t1^ans。把数组下标为pos的数,数值+1e7;

操作2:给你t2,t3。r=t2^ans,k=t3^ans。输出**与数组下标1~r的数不同**且**不小于k**的最小数。更新ans。

数据范围:

1≤T≤10,1≤n≤1e5,1≤m≤1e5,1≤a[i]≤n,a[i]各不相同,1posn,1≤r≤n,1≤k≤n。

n510,000,m510,000。

 

赛后补题。

 

此处照搬标准题解:

因为数组中的值唯一,且在1到n的范围内,而询问的r和k也在1到n的范围内。 所以对于任意一个被操 作1修改过的值都不会成为询问的答案,而询问的结果也必然在k到n+1的范围内。 因为没有被修改过 值是唯一的,所以可以建立权值线段树,维护权值区间内的值所在下标的最大值。而询问则转化为不小 于k的值里面,下标超过r的最小权值是多少。 如何处理询问呢,一种较为暴力的解法是直接在线段树上 询问权值在k到n+1的范围内第一个下标超过r的权值是多少。但复杂度可能会被卡,需要减枝。 再加上 一个额外的判断就可以了,就是在递归查询完左子树内存不存在大于r的下标之后,如果不存在,则先 看一下右子树内的下标的最大值是否大于r。如果不大于r,则不必再进入右子树内查询,否则答案一定 在右子树内。在进左子树之前也利用同样的判断条件来判断是否有必要进入左子树,这样做可以保证单 次查询的复杂度是O(log n) 的。 而对于操作1,则等价于修改某个权值的下标为无穷大。操作复杂度也 是O(log n )的。 综上所述,得到了一个复杂度为O( m * log n )的在线算法,可以较快地通过此题。 

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;
const int inf=0x3f3f3f3f;
struct P{
    int l,r,id;
}tree[maxn<<2];
void build(int l,int r,int k)
{
    tree[k].l=l;tree[k].r=r;    
    if(tree[k].l==tree[k].r)
    {
        tree[k].id=0;        
        return ;
    }    
    int mid=(tree[k].l+tree[k].r)/2;
    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
    tree[k].id=0;
}
void add(int x,int id,int k)
{
    if(tree[k].l==tree[k].r)
    {
        tree[k].id=id;return;
    }
    int mid=(tree[k].l+tree[k].r)/2;
    if(x<=mid)add(x,id,k*2);
    else add(x,id,k*2+1);
    tree[k].id=max(tree[k*2].id,tree[k*2+1].id);
}
int find(int l,int r,int k,int minid)
{
    if(tree[k].l==tree[k].r)
    {
        if(tree[k].id>minid)return l;
        return inf;
    }
    if(tree[k].id<=minid)return inf;
    int mid=(tree[k].l+tree[k].r)/2;
    int id1=tree[k*2].id,id2=tree[k*2+1].id;
    if(r<=mid)
    {
        if(id1<=minid)return inf;
        return find(l,r,k*2,minid);
    }
    if(l>mid)
    {
        if(id2<=minid)return inf;
        return find(l,r,k*2+1,minid);
    }
    int ans1=inf,ans2=inf,ans=inf;
    if(id1>minid)ans1=find(l,mid,k*2,minid);
    if(id2>minid&&ans1==inf)ans2=find(mid+1,r,k*2+1,minid);
    ans=min(ans1,ans2);
    return ans;
}
/*void f(int l,int r,int k)
{
    printf("##l:%d ##r:%d##id:%d\n",tree[k].l,tree[k].r,tree[k].id);
    if(tree[k].l==tree[k].r)return;
    int mid=(tree[k].l+tree[k].r)/2;
    f(l,mid,k*2);
    f(l,mid,k*2+1);
}*/
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,op,t1,t2,t3,i,a[maxn],ans=0;
        scanf("%d%d",&n,&m);
        build(1,n,1);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            add(a[i],i,1);
        }
        //f(1,n,1);
        for(i=1;i<=m;i++)
        {
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d",&t1);
                add(a[t1^ans],inf,1);
                //f(1,n,1);
                continue;
            }
            scanf("%d%d",&t2,&t3);
            t2^=ans;t3^=ans;
            ans=find(t3,n,1,t2);
            //printf("@@r:%d k:%d@@ans:",t2,t3);
            if(ans!=inf)printf("%d\n",ans);
            else{
                ans=n+1;
                printf("%d\n",ans);
            }
        }
        //puts("############");
    }
}

 

2019CCPC网络选拔赛 array(权值线段树)

标签:const   void   处理   数组下标   build   超过   bit   return   内存   

原文地址:https://www.cnblogs.com/kkkek/p/11441193.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!