高一上七月下旬日记
7.21
闲话
- 以为体活食堂能早点开门,遂睡到 \(6:25\) 就起来去食堂了,结果 \(6:40\) 才开门。到机房刷脸打卡的时候是 \(7:00:43\) 左右。
- 上午 \(7:30 \sim 11:30\) @Delov 学长安排了一场模拟赛。
- 模拟赛打到一半被 \(field\) 叫回宿舍整改内务,说 \(huge\) 已经在宿舍等我们了。“放风”一半发现 \(feifei\) 也从后面追来了,遂跑着回到宿舍整改内务。走的时候 \(huge\) 说以后集训就按今天的标准,下周领导视察很多,别出问题。
- 午休 \(huge\) 查宿。
- 下午 \(huge\) 来说了今年国赛的情况,说了下 \(NOI\) 向类 \(IOI\) 赛制转变对 \(HZOI\) 的影响;举了 @APJifengc 的例子; \(D\) 了下他们模拟赛遇到比较难写的题选择口胡而不写代码,说早期几届学长经常写一些码量比较大的题,但现在选择写这种题的人越来越少了。
- 晚上加赛。
- 晚休 \(field\) 查宿。
做题纪要
CF685B Kay and Snowflake
-
对于每组询问遍历一遍整棵子树不可接受。
-
接着考虑重心的一些性质。
- 以 \(x\) 为根的子树的重心一定在以 \(x\) 的所有子节点为根的子树的重心到 \(x\) 的路径上。
-
求出重心后暴力向上跳即可。
点击查看代码
struct node { int nxt,to; }e[600010]; int head[600010],siz[600010],weight[600010],ans[600010],fa[600010],cnt=0; void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(int x,int father) { siz[x]=1; fa[x]=father; weight[x]=0; ans[x]=x; for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dfs(e[i].to,x); siz[x]+=siz[e[i].to]; weight[x]=max(weight[x],siz[e[i].to]); } } for(int i=head[x];i!=0;i=e[i].nxt) { int y=ans[e[i].to]; while(y!=x) { if(max(weight[y],siz[x]-siz[y])<=siz[x]/2) { ans[x]=y; break; } else { y=fa[y]; } } } } int main() { int n,m,u,v,i; cin>>n>>m; for(i=2;i<=n;i++) { cin>>u; v=i; add(u,v); } dfs(1,0); for(i=1;i<=m;i++) { cin>>u; cout<<ans[u]<<endl; } return 0; }
CF958C3 Encryption (hard)
[ARC148C] Lights Out on Tree
[ARC153C] ± Increasing Sequence
luogu P2056 [ZJOI2007] 捉迷藏
- 多倍经验: luogu P4115 Qtree4 | SP2666 QTREE4 - Query on a tree IV
- 详见 暑假集训CSP提高模拟4 T4 P136. Black and White 。
7.22
闲话
- 上午 @worldvanquisher 讲了 \(BSGS\) , \(Prüfer\) 序 列,莫反,拉格朗日插值; @Chen_jr 讲了基环树。原容斥被换成了拉格朗日插值。
做题纪要
CF958C2 Encryption (medium)
-
同 CF958C3 Encryption (hard) ,取使 \(f_{h,j-1}\) 取到最大值的 \(h\) 即可。
点击查看代码
ll a[500010],sum[500010],f[500010][2]; int main() { ll n,k,p,maxx,pos,i,j; scanf("%lld%lld%lld",&n,&k,&p); for(i=1;i<=n;i++) { scanf("%lld",&a[i]); sum[i]=sum[i-1]+a[i]; } f[0][0]=0; for(j=1;j<=k;j++) { maxx=f[j-1][(j-1)&1]; pos=j-1; for(i=j;i<=n;i++) { f[i][j&1]=f[pos][(j-1)&1]+(sum[i]-sum[pos])%p; if(f[i][(j-1)&1]>maxx) { maxx=f[i][(j-1)&1]; pos=i; } } } printf("%lld\n",f[n][k&1]); return 0; }
P145 修仙(restart)
luogu P2617 Dynamic Rankings
- 树状数组套主席树板子。
- 每次修改都会对后续操作产生影响,对主席树进行暴力修改时空复杂度均不能接受。考虑树状数组来维护变化的过程。
- 树状数组的每一个节点都是一颗主席树(叫做动态开点权值线段树可能更合适)。
- 操作中的修改就能转化成单点修改,查询时将设计到的树状数组的节点提出来进行询问。
-
若将原树的点也看做修改操作,时空复杂度为 \(O((n+m)\log^{2} n)\) 。
点击查看代码
struct ask { int l,r,k; char pd; }q[200010]; int a[200010],b[200010]; struct PDS_SMT { int root[200010],rt_sum=0; struct SegmentTrew { int ls,rs,sum; }tree[200010<<8]; #define lson(rt) tree[rt].ls #define rson(rt) tree[rt].rs int build_rt() { rt_sum++; return rt_sum; } void build_tree(int &rt,int l,int r) { rt=build_rt(); if(l==r) { return; } int mid=(l+r)/2; build_tree(lson(rt),l,mid); build_tree(rson(rt),mid+1,r); } void update(int &rt,int l,int r,int pos,int val) { rt=(rt==0)?build_rt():rt; tree[rt].sum+=val; if(l==r) { return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(rt),l,mid,pos,val); } else { update(rson(rt),mid+1,r,pos,val); } } int query(int rt1[],int len1,int rt2[],int len2,int l,int r,int k) { if(l==r) { return l; } int mid=(l+r)/2,sum=0; for(int i=1;i<=len2;i++) { sum+=tree[lson(rt2[i])].sum; } for(int i=1;i<=len1;i++) { sum-=tree[lson(rt1[i])].sum; } if(k<=sum) { for(int i=1;i<=len2;i++) { rt2[i]=lson(rt2[i]); } for(int i=1;i<=len1;i++) { rt1[i]=lson(rt1[i]); } return query(rt1,len1,rt2,len2,l,mid,k); } else { for(int i=1;i<=len2;i++) { rt2[i]=rson(rt2[i]); } for(int i=1;i<=len1;i++) { rt1[i]=rson(rt1[i]); } return query(rt1,len1,rt2,len2,mid+1,r,k-sum); } } }T; struct BIT { int rt[2][32]; int lowbit(int x) { return (x&(-x)); } void add(int n,int x,int val) { int pos=lower_bound(b+1,b+1+b[0],a[x])-b; for(int i=x;i<=n;i+=lowbit(i)) { T.update(T.root[i],1,b[0],pos,val); } } int query(int l,int r,int k) { memset(rt,0,sizeof(rt)); for(int i=r;i>=1;i-=lowbit(i)) { rt[1][0]++; rt[1][rt[1][0]]=T.root[i]; } for(int i=l-1;i>=1;i-=lowbit(i)) { rt[0][0]++; rt[0][rt[0][0]]=T.root[i]; } return T.query(rt[0],rt[0][0],rt[1],rt[1][0],1,b[0],k); } }B; int main() { int n,m,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; b[0]++; b[b[0]]=a[i]; } for(i=1;i<=m;i++) { cin>>q[i].pd>>q[i].l>>q[i].r; if(q[i].pd=='Q') { cin>>q[i].k; } else { b[0]++; b[b[0]]=q[i].r; } } sort(b+1,b+1+b[0]); b[0]=unique(b+1,b+1+b[0])-(b+1); for(i=1;i<=n;i++) { B.add(n,i,1); } for(i=1;i<=m;i++) { if(q[i].pd=='Q') { cout<<b[B.query(q[i].l,q[i].r,q[i].k)]<<endl; } else { B.add(n,q[i].l,-1); a[q[i].l]=q[i].r; B.add(n,q[i].l,1); } } return 0; }
-
不将原树的点看做修改操作,开始时建立一棵静态主席树,查询时把主席树也提出来进行询问,时空复杂度为 \(O(n \log n+m \log^{2} n)\) 。
点击查看代码
struct ask { int l,r,k; char pd; }q[200010]; int a[200010],b[200010]; struct PDS_SMT { int root1[200010],root2[200010],rt_sum=0; struct SegmentTrew { int ls,rs,sum; }tree[200010<<5]; #define lson(rt) tree[rt].ls #define rson(rt) tree[rt].rs int build_rt() { rt_sum++; return rt_sum; } void build_tree(int &rt,int l,int r) { rt=build_rt(); if(l==r) { return; } int mid=(l+r)/2; build_tree(lson(rt),l,mid); build_tree(rson(rt),mid+1,r); } void update1(int pre,int &rt,int l,int r,int pos) { rt=build_rt(); tree[rt]=tree[pre]; tree[rt].sum++; if(l==r) { return; } int mid=(l+r)/2; if(pos<=mid) { update1(lson(pre),lson(rt),l,mid,pos); } else { update1(rson(pre),rson(rt),mid+1,r,pos); } } void update2(int &rt,int l,int r,int pos,int val) { rt=(rt==0)?build_rt():rt; tree[rt].sum+=val; if(l==r) { return; } int mid=(l+r)/2; if(pos<=mid) { update2(lson(rt),l,mid,pos,val); } else { update2(rson(rt),mid+1,r,pos,val); } } int query(int rt1[],int len1,int rt2[],int len2,int l,int r,int k) { if(l==r) { return l; } int mid=(l+r)/2,sum=0; for(int i=1;i<=len2;i++) { sum+=tree[lson(rt2[i])].sum; } for(int i=1;i<=len1;i++) { sum-=tree[lson(rt1[i])].sum; } if(k<=sum) { for(int i=1;i<=len2;i++) { rt2[i]=lson(rt2[i]); } for(int i=1;i<=len1;i++) { rt1[i]=lson(rt1[i]); } return query(rt1,len1,rt2,len2,l,mid,k); } else { for(int i=1;i<=len2;i++) { rt2[i]=rson(rt2[i]); } for(int i=1;i<=len1;i++) { rt1[i]=rson(rt1[i]); } return query(rt1,len1,rt2,len2,mid+1,r,k-sum); } } }T; struct BIT { int rt[2][32]; int lowbit(int x) { return (x&(-x)); } void add(int n,int x,int val) { int pos=lower_bound(b+1,b+1+b[0],a[x])-b; for(int i=x;i<=n;i+=lowbit(i)) { T.update2(T.root2[i],1,b[0],pos,val); } } int query(int l,int r,int k) { memset(rt,0,sizeof(rt)); for(int i=r;i>=1;i-=lowbit(i)) { rt[1][0]++; rt[1][rt[1][0]]=T.root2[i]; } rt[1][0]++; rt[1][rt[1][0]]=T.root1[r]; for(int i=l-1;i>=1;i-=lowbit(i)) { rt[0][0]++; rt[0][rt[0][0]]=T.root2[i]; } rt[0][0]++; rt[0][rt[0][0]]=T.root1[l-1]; return T.query(rt[0],rt[0][0],rt[1],rt[1][0],1,b[0],k); } }B; int main() { int n,m,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; b[0]++; b[b[0]]=a[i]; } for(i=1;i<=m;i++) { cin>>q[i].pd>>q[i].l>>q[i].r; if(q[i].pd=='Q') { cin>>q[i].k; } else { b[0]++; b[b[0]]=q[i].r; } } sort(b+1,b+1+b[0]); b[0]=unique(b+1,b+1+b[0])-(b+1); T.build_tree(T.root1[0],1,b[0]); for(i=1;i<=n;i++) { T.update1(T.root1[i-1],T.root1[i],1,b[0],lower_bound(b+1,b+1+b[0],a[i])-b); } for(i=1;i<=m;i++) { if(q[i].pd=='Q') { cout<<b[B.query(q[i].l,q[i].r,q[i].k)]<<endl; } else { B.add(n,q[i].l,-1); a[q[i].l]=q[i].r; B.add(n,q[i].l,1); } } return 0; }
-
- 离散化来减小常数。
luogu [CQOI2015] 任务查询系统
luogu P3302 [SDOI2013] 森林
luogu P3722 [AH2017/HNOI2017] 影魔
BZOJ4026 dC Loves Number Theory
luogu P4587 [FJOI2016] 神秘数
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18315250,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。