zoukankan      html  css  js  c++  java
  • bzoj4571: [Scoi2016]美味

    这道题想了好几天了。。。可持久化trie完全做不动

    然后不知道谁给了个路牌,今天突然会了

    拿个主席树来,维护一下权值线段树,一开始我们想让最高位为1,那么就看看对于b取0还是1,假如没有加的操作,区间就是0~2^j-1上的数该位是0,2^j~2^(j+1)-1是1,加上的数就相当于这些区间都减掉这个数,据此用类似可持久化trie的思想,在左右区间找并不断更新区间lr即可

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    struct chairman
    {
        int lc,rc,c;
    }tr[6100000];int trlen,rt[210000];
    int maketree(int x,int l,int r,int p)
    {
        if(x==0)
        {
            x=++trlen;
            tr[x].lc=tr[x].rc=0;
        }
        tr[x].c++;
        
        if(l<r)
        {
            int mid=(l+r)/2;
            if(p<=mid)tr[x].lc=maketree(tr[x].lc,l,mid,p);
            else       tr[x].rc=maketree(tr[x].rc,mid+1,r,p);
        }
        return x;
    }
    int merge(int x,int y)
    {
        if(x==0||y==0)return x+y;
        tr[x].c+=tr[y].c;
        tr[x].lc=merge(tr[x].lc,tr[y].lc);
        tr[x].rc=merge(tr[x].rc,tr[y].rc);
        return x;
    }
    bool check(int x,int y,int ml,int mr,int l,int r)
    {
        if(l<0)l=0;
        if(x==0&&y==0)return false;
        if(ml==l&&mr==r)return (tr[y].c-tr[x].c)>0;
        
        int mid=(ml+mr)/2;
             if(r<=mid)  return check(tr[x].lc,tr[y].lc,ml,mid,l,r);
        else if(mid+1<=l)return check(tr[x].rc,tr[y].rc,mid+1,mr,l,r);
        else return check(tr[x].lc,tr[y].lc,ml,mid,l,mid)|check(tr[x].rc,tr[y].rc,mid+1,mr,mid+1,r);
    }
    
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        int n,Q,x;
        scanf("%d%d",&n,&Q);
        trlen=0;memset(rt,0,sizeof(rt));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            rt[i]=maketree(rt[i],0,(1<<23)-1,x);
            rt[i]=merge(rt[i],rt[i-1]);
        }
        
        while(Q--)
        {
            int g,d,st,ed;
            scanf("%d%d%d%d",&g,&d,&st,&ed);
            
            int L=-d,R=(1<<23)-1-d,ans=0;
            for(int i=22;i>=0;i--)
            {
                int mid=(L+R)>>1;
                int x=(g&(1<<i));
                if(x==0)
                {
                    if(check(rt[st-1],rt[ed],0,(1<<23)-1,mid+1,R))
                        ans+=(1<<i), L=mid+1;
                    else
                        R=mid;
                }
                else
                {
                    if(check(rt[st-1],rt[ed],0,(1<<23)-1,L,mid))
                        ans+=(1<<i), R=mid;
                    else
                        L=mid+1;
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    LED点阵显示
    KEIL安装
    KEIL安装
    ubuntu安装svn
    python基础-面向过程编程
    js遇到代码出现问题时如何调试代码
    js内置对象的常用属性和方法(Array | String | Date | Math)
    js函数的使用+封装+代码复用
    JavaScript中条件分支语句和循环语句的使用,用简洁的代码实现强大功能
    JavaScript的语法、数据类型、基本算数和逻辑运算操作
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/9650086.html
Copyright © 2011-2022 走看看