9.27数据结构练习赛

来源:互联网 发布:层次方框图软件 编辑:程序博客网 时间:2024/05/22 09:06

这里写图片描述# 欢迎使用Markdown编辑器写博客
题解:莫队算法模板题!
当然也可以用线段树解决:
离线+ 线段树
将询问R 值排序,考虑维护一个数组A,表示当前询问R 值确定,对于每
一个L 值答案是多少
假设一直R-1 时的数组A’,我们需要求R 的数组A
预处理处每个位置相同值的上一次出现位置prv[i]。
那么对于A 数组中所有prv[r]+1 到r 的位置,都要加v[r],因为这些位置
到r 的区间v[r] 只出现过1 次。
同理prv[prv[r]]+1 到prv[r] 需要-v[r]
同理prv[prv[prv[r]]]+1 到prv[prv[r]] 需要+3*v[r]
同理1 到prv[prv[prv[r]]] 需要+v[r]
区间修改单点查询,线段树或树状数组都可以。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>using namespace std;typedef long long ll;const int MAXN=1e5+4;int n,m,siz;int cnt[MAXN],num[MAXN],bel[MAXN];ll ans[MAXN],ret=0;struct Q {    int l,r,id;    friend bool operator <(const Q &x,const Q &y) {        return bel[x.l]==bel[y.l]?x.r<y.r:x.l<y.l;    }}q[MAXN];inline int read() {    int x=0,f=1;char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();    return x*f;}int main() {    freopen("abnormal.in","r",stdin);    freopen("abnormal.out","w",stdout);    n=read(),m=read(),siz=(int)sqrt((double)n);    for (register int i=1;i<=n;++i) num[i]=read(),bel[i]=i/siz;    for (register int i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;    sort(q+1,q+m+1);    for (register int i=1,l=1,r=0;i<=m;++i) {        while (l>q[i].l) {            ++cnt[num[--l]];            ret+=num[l];            if (cnt[num[l]]==3) ret+=(num[l]<<1);            if (cnt[num[l]]==2) ret-=(num[l]<<1);        }        while (r<q[i].r) {            ++cnt[num[++r]];            ret+=num[r];            if (cnt[num[r]]==3) ret+=(num[r]<<1);            if (cnt[num[r]]==2) ret-=(num[r]<<1);        }        while (l<q[i].l) {            --cnt[num[l++]];            ret-=num[l-1];            if (cnt[num[l-1]]==1) ret+=(num[l-1]<<1);            if (cnt[num[l-1]]==2) ret-=(num[l-1]<<1);        }        while (r>q[i].r) {            --cnt[num[r--]];            ret-=num[r+1];            if (cnt[num[r+1]]==1) ret+=(num[r+1]<<1);            if (cnt[num[r+1]]==2) ret-=(num[r+1]<<1);        }        ans[q[i].id]=ret;    }    for (register int i=1;i<=m;++i) printf("%I64d\n",ans[i]);    return 0;}

这里写图片描述
题解:trie+ 启发式合并
首先,预处理处每个节点到根节点路径异或和v[x]
则x,y 路径异或和为v[x] xor v[y] xor a[lca(x,y)]
其次,我们可以通过trie 树贪心来O(log) 求出一个集合和一个数的异或最
大值。
最后,集合的合并如果每次都将小的合并到大的上面去,复杂度O(nlogn),
名叫启发式合并
于是这道题我们就可以用trie 维护子树v 值的集合,并通过启发式合并向
上进行。每次贪心找最大路径异或和

题解2:树链剖分+可持久化Trie
大概就是用双指针扫当前子树对应的dfs序区间,每次处理后r就往后移,而起点l不动,相当于就是将处理过的启发式合并!由于时间复杂度限制,需要树链剖分来优化对重儿子的处理。由于这样的优化只能用一次,所以肯定选size最大的儿子即重儿子来优化。为什么只能用一次呢,因为只有第一次Trie_query是第1个儿子区间与当前根的询问,后面就是第i个儿子与(根+第1个儿子区间+第2个儿子区间+…+第i-1个儿子区间)询问。
我估计我说了还是没几个人看得懂,所以附上大佬的博客地址orz
戳这里看大佬的原创解法

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<utility>using namespace std;#define pii pair<int,int>#define mp(x,y) make_pair(x,y)const int MAXN=1e5+4;int n,head[MAXN],edge=0;struct EDGE {    int v,nxt;}e[MAXN<<1];int siz[MAXN],in[MAXN],out[MAXN],rk[MAXN],son[MAXN],fa[MAXN],dis[MAXN],tim=0;int a[MAXN],seq[MAXN];inline int read() {    int x=0;char c=getchar();    while (c<'0'||c>'9') c=getchar();    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();    return x;}inline void adde(int u,int v) {    e[edge].nxt=head[u],e[edge].v=v,head[u]=edge++;    e[edge].nxt=head[v],e[edge].v=u,head[v]=edge++;}/*----------DCP----------*/void dfs1(int p,int f) {    siz[p]=1,fa[p]=f;    for (int i=head[p];~i;i=e[i].nxt) {        int v=e[i].v;        if (v^f) {            dis[v]=dis[p]^a[v];            dfs1(v,p);            siz[p]+=siz[v];            if (son[p]==-1||siz[son[p]]<siz[v]) son[p]=v;        }    }}void dfs2(int p) {    in[p]=++tim,rk[in[p]]=p;    seq[tim]=dis[p];    if (son[p]==-1) {out[p]=tim;return ;}    dfs2(son[p]);//保证先dfs重儿子    for (int i=head[p];~i;i=e[i].nxt) {        int v=e[i].v;        if (v^fa[p]&&v^son[p])            dfs2(v);     }    out[p]=tim;}/*----------Persistent Trie----------*/struct TRIE {    int son[2],w;    TRIE() {w=0;}}t[MAXN*33];int tot=0,root[MAXN];void Insert(int pre,int &rt,int d,int step) {    t[rt=++tot]=t[pre];    ++t[rt].w;    if (step<0) return ;    int p=(d>>step)&1;     Insert(t[pre].son[p],t[rt].son[p],d,step-1);}int query(int d,int pre,int rt,int step) {    if (step<0) return 0;    int p=(d>>step)&1;    if (t[t[rt].son[!p]].w-t[t[pre].son[!p]].w)        return (1<<step)+query(d,t[pre].son[!p],t[rt].son[!p],step-1);    else return query(d,t[pre].son[p],t[rt].son[p],step-1);}int main() {    freopen("irregular.in","r",stdin);    freopen("irregular.out","w",stdout);    memset(head,-1,sizeof(head));    memset(son,-1,sizeof(son));    n=read();    for (register int i=1;i<=n;++i) a[i]=read();    for (register int i=1;i<n;++i) {        int u=read(),v=read();        adde(u,v);    }    dis[1]=a[1];    dfs1(1,0);    dfs2(1);//  for (int i=1;i<=n;++i) printf("%d %d %d %d\n",in[i],out[i],dis[i],seq[i]);    for (register int i=1;i<=tim;++i) Insert(root[i-1],root[i],seq[i],31);    int l,r,v;    for (register int i=1;i<=n;++i) {        int ans=a[i];        if (fa[rk[in[i]+1]]==i) {            v=son[rk[in[i]]];//=rk[in[i]+1]            l=in[v],r=out[v];            ans=max(ans,query(seq[in[i]]^a[i],root[l-1],root[r],31));            l=in[i];        }        else {            printf("%d ",ans);            continue;        }        while (fa[rk[out[v]+1]]==i) {            v=rk[out[v]+1];            for (int p=in[v];p<=out[v];++p)                ans=max(ans,query(seq[p]^a[i],root[l-1],root[r],31));            r=out[v];        }        printf("%d ",ans);    }    return 0;}

这里写图片描述
题解:双堆维护动态中位数,本来大部分平衡树是可以实现的但是被卡了,于是有些大佬就写了RBT,orzorzorz。

双堆实现:

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>using namespace std;typedef long long ll;const int MAXN=1e6+4,MOD=1e9+7;int a,b,c,n,f;ll ret=1;priority_queue<int, vector<int>, less<int> > qmax;//bigger rootpriority_queue<int, vector<int>, greater<int> > qmin;//smaller rootinline void add(int x) {    if (qmin.empty()) {qmin.push(x);return ;}    if (x>qmin.top()) qmin.push(x);    else qmax.push(x);    if (qmin.size()<qmax.size()) {//while        qmin.push(qmax.top());        qmax.pop();    }    if (qmin.size()>qmax.size()+1) {//while        qmax.push(qmin.top());        qmin.pop();    }}int main() {    freopen("unnormal.in","r",stdin);    freopen("unnormal.out","w",stdout);    scanf("%d%d%d%d",&a,&b,&c,&n);    add(1);    for (register int i=2;i<=n;++i) {        add(f);        f=(1ll*a*qmin.top()+1ll*b*i+c)%MOD;        ret+=f;    }    cout<<ret<<endl;    return 0;}

RBT实现:

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int MAXN=1e6+4,MOD=1e9+7;int a,b,c,n;int f[MAXN];ll ret=1;struct RBt{    int data,s,c;    bool col;    RBt *fa,*ch[2];    inline void set(int _v,bool _col,int i,RBt *p){        data=_v,col=_col,s=c=i;        fa=ch[0]=ch[1]=p;    }    inline void push_up(){s=ch[0]->s+ch[1]->s+c;}    inline void push_down(){for(RBt *x=this; x->s; x=x->fa)x->s--;}    inline int cmp(int v)const{return data==v?-1:v>data;}};struct RedBlackTree{    int top;    RBt *root,*null;    RBt stack[MAXN],*tail,*se[MAXN];    void init(){        tail=&stack[0],null=tail++;        null->set(0,0,0,NULL);        root=null,top=0;    }    inline RBt *newRBt(int v){        RBt *p=null;        if(!top)p=tail++;else p=se[--top];        p->set(v,1,1,null);        return p;    }    inline void rotate(RBt* &x,bool d ){        RBt *y=x->ch[!d];        x->ch[!d]=y->ch[d];        if(y->ch[d]->s)y->ch[d]->fa=x;y->fa=x->fa;        if(!x->fa->s)root=y;else x->fa->ch[x->fa->ch[0]!=x]=y;        y->ch[d]=x,x->fa=y,y->s=x->s,x->push_up();    }    inline void insert(int v){        RBt *x=root,*y=null;        while(x->s){            x->s++,y=x;            int d=x->cmp(v);            if(-1==d){x->c++;return;}            x=x->ch[d];        }        x=newRBt(v);        if(y->s)y->ch[v>y->data]=x;else root=x;        x->fa=y;insert_fix(x);    }    inline void insert_fix(RBt* &x){        while(x->fa->col){            RBt *par=x->fa,*Gp=par->fa;            bool d=par==Gp->ch[0];            RBt *uncle=Gp->ch[d];            if(uncle->col)par->col=uncle->col=0,Gp->col=1,x=Gp;            else if(x==par->ch[d])rotate(x=par,!d);            else Gp->col=1,par->col=0,rotate(Gp,d);        }        root->col=0;    }    inline RBt *find(RBt *x,int data){        while(x->s&&x->data != data)x=x->ch[x->data < data];        return x;    }    inline int kth(int k){        int t;        RBt *x=root;        for(; x->s;){            t=x->ch[0]->s;            if(k<=t)x=x->ch[0];            else if(t+1<=k&&k<=t+x->c)break;            else k-=t+x->c,x=x->ch[1];        }        return x->data;    }}rbt;int main() {    freopen("unnormal.in","r",stdin);    freopen("unnormal.out","w",stdout);    scanf("%d%d%d%d",&a,&b,&c,&n);    rbt.init();    rbt.insert(f[1]=1);    for (register int i=2;i<=n;++i) {        int temp=i>>1;        int M=rbt.kth(temp);        f[i]=(1ll*a*M%MOD+1ll*b*i%MOD+c)%MOD;        rbt.insert(f[i]);        ret+=f[i];    }    cout<<ret<<endl;    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 王者荣耀太卡了怎么办 想卖王者号qq怎么办 小米4电视发热严重怎么办 三星玩王者荣耀卡怎么办 华为麦芒5网络差怎么办 华为麦芒无线信号不好怎么办 华为麦芒6网络不好怎么办 华为麦芒6信号差怎么办 华为手机无线网信号差怎么办 华为麦芒6数据信号差怎么办 华为麦芒54g信号差怎么办 华为手机wifi信号差怎么办 华为手机导航信号弱怎么办 华为手机gps信号弱怎么办 麦芒5指纹消失了怎么办 华为应用锁密码忘了怎么办 华为麦芒5密码忘了怎么办 华为卡1无服务怎么办 经常卡1无服务怎么办 华为手机进水无服务怎么办 苹果手机进水后无服务怎么办 苹果6进水无服务怎么办 华为手机突然无服务怎么办 sim卡显示无服务怎么办 华为麦芒进水无限开关机怎么办 华为麦芒5进水黑屏怎么办 华为麦芒6进水了怎么办 4g手机开不开机怎么办 全屏钢化膜总是翘边怎么办 华为麦芒屏幕触屏失灵怎么办 华为麦芒5运行慢怎么办 手机屏保密码忘记了怎么办 麦芒5密码锁忘了怎么办 超薄手机壳松了怎么办 华为麦芒5声音小怎么办 笔记本外壳a面裂了怎么办 苹果手机外壳摔坏了怎么办 挂衣服肩膀出包怎么办 摩拜单车手机号注销了怎么办 摩拜单车手机号码换了怎么办 摩拜单车换手机号码打不开怎么办