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;}
- 9.27数据结构练习赛
- 9.26数据结构练习赛
- 数据结构练习
- P2320 - 【长郡模拟赛】数据结构练习
- 数据结构练习:排序
- 数据结构练习:排序
- 数据结构练习:堆栈
- 数据结构练习:快速排序
- 数据结构与算法练习
- 数据结构实现练习
- 数据结构与算法练习
- 【数据结构练习】简单四则运算
- 数据结构---数组操作练习
- 数据结构练习程序
- 基本数据结构练习
- 数据结构练习 3/30
- 数据结构--递归练习
- 001数据结构练习-前言
- 字符串的全排列问题的解决方法
- Ubuntu16.04环境下安装CUDA、cudnn、Caffe、Tensorflow、pytorch
- socket、tcp、udp、http 的认识及区别
- linux Samba共享,图形界面配置
- 洛谷P3606 [USACO17JAN]Building a Tall Barn建谷仓
- 9.27数据结构练习赛
- Codevs 2185 LCIS
- Android 恢复出厂设置(recovery)
- CC2541开发板(TI官方)类型介绍
- 新人降临
- Day10
- Java设计模式-迭代器模式
- JAVA不可修改类
- MVP