8.数据结构
数据结构
开题顺序:
CF2042D Recommendations
-
扫描线维护
的最大值和 的最小值。点击查看代码
int l[200010],r[200010],d[200010],st[200010],ed[200010]; vector<pair<int,int> >q[200010]; multiset<int>s; multiset<int>::iterator it; void slove1(int n) { s.clear(); for(int i=1;i<=n;i++) { q[i].clear(); d[i]=r[i]; } sort(d+1,d+1+n); d[0]=unique(d+1,d+1+n)-(d+1); for(int i=1;i<=n;i++) q[lower_bound(d+1,d+1+d[0],r[i])-d].push_back(make_pair(l[i],i)); for(int i=d[0];i>=1;i--) { sort(q[i].begin(),q[i].end()); for(int j=0;j<q[i].size();j++) s.insert(q[i][j].first); for(int j=0;j<q[i].size();j++) { s.erase(s.find(q[i][j].first)); it=s.upper_bound(q[i][j].first); if(it!=s.begin()&&s.empty()==0) st[q[i][j].second]=*prev(it); s.insert(q[i][j].first); } } } void slove2(int n) { s.clear(); for(int i=1;i<=n;i++) { q[i].clear(); d[i]=l[i]; } sort(d+1,d+1+n); d[0]=unique(d+1,d+1+n)-(d+1); for(int i=1;i<=n;i++) q[lower_bound(d+1,d+1+d[0],l[i])-d].push_back(make_pair(r[i],i)); for(int i=1;i<=d[0];i++) { sort(q[i].begin(),q[i].end(),greater<pair<int,int> >()); for(int j=0;j<q[i].size();j++) s.insert(q[i][j].first); for(int j=0;j<q[i].size();j++) { s.erase(s.find(q[i][j].first)); it=s.lower_bound(q[i][j].first); if(it!=s.end()&&s.empty()==0) ed[q[i][j].second]=*it; s.insert(q[i][j].first); } } } int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int t,n,i,j; cin>>t; for(j=1;j<=t;j++) { cin>>n; for(i=1;i<=n;i++) st[i]=ed[i]=0x3f3f3f3f; for(i=1;i<=n;i++) cin>>l[i]>>r[i]; slove1(n); slove2(n); for(i=1;i<=n;i++) cout<<(st[i]!=0x3f3f3f3f&&ed[i]!=0x3f3f3f3f)*((ed[i]-st[i]+1)-(r[i]-l[i]+1))<<endl; } return 0; }
HDU5603 the soldier of love
-
正难则反,考虑统计不包含组中任意一个给定点的段数,划分成
段区间后扫描线维护。点击查看代码
int l[300010],r[300010],x[300010],ans[300010]; vector<int>c[1000010]; vector<pair<int,int> >q[1000010]; struct BIT { int c[1000010]; void clear() { memset(c,0,sizeof(c)); } int lowbit(int x) { return (x&(-x)); } void add(int n,int x,int val) { for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val; } int getsum(int x) { int ans=0; for(int i=x;i>=1;i-=lowbit(i)) ans+=c[i]; return ans; } }T; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,m,k,i,j; while(scanf("%d%d",&n,&m)==2) { T.clear(); for(i=1;i<=n;i++) { scanf("%d%d",&l[i],&r[i]); c[l[i]].push_back(r[i]); } for(i=1;i<=m;i++) { scanf("%d",&k); ans[i]=0; x[0]=0; x[k+1]=1000001; for(j=1;j<=k;j++) scanf("%d",&x[j]); for(j=1;j<=k+1;j++) { if(x[j]-1>=x[j-1]+1) q[x[j-1]+1].push_back(make_pair(x[j]-1,i)); } } for(i=1000000;i>=1;i--) { for(j=0;j<c[i].size();j++) T.add(1000000,c[i][j],1); for(j=0;j<q[i].size();j++) ans[q[i][j].second]+=T.getsum(q[i][j].first); c[i].clear(); q[i].clear(); } for(i=1;i<=m;i++) printf("%d\n",n-ans[i]); } return 0; }
UOJ 637. 【美团杯2021】A. 数据结构
-
正难则反。观察到
对答案产生贡献当且仅当所有的 都在 内且 中不含有 。不妨先假设所有出现过的元素都对所有区间产生 的贡献,然后维护变化的贡献。 -
像上题一次性划分成若干段区间后难以进行数颜色,但可以借鉴划分区间的思想,在扫描线的过程中划分并更新答案。
-
设
的极长存在区间为 。对右端点进行扫描线的过程中,考虑维护每个元素会对什么样的询问产生贡献。 -
针对第二个限制,
会对询问左端点 的答案产生 的贡献。 -
针对第一个限制,当
时, 无法对询问左端点 的询问产生贡献,故减 。点击查看代码
int a[1000010],st[1000010],ed[1000010],ans[1000010],last[1000010]; vector<pair<int,int> >q[1000010]; struct BIT { int c[1000010]; int lowbit(int x) { return (x&(-x)); } void add(int n,int x,int val) { for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val; } void update(int n,int l,int r,int val) { add(n,l,val); add(n,r+1,-val); } int getsum(int x) { int ans=0; for(int i=x;i>=1;i-=lowbit(i)) ans+=c[i]; return ans; } }T; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,m,sum=0,l,r,i,j; scanf("%d%d",&n,&m); fill(st+0,st+n+2,n+1); for(i=1;i<=n;i++) { scanf("%d",&a[i]); if(st[a[i]]==n+1) { st[a[i]]=i; sum++; } ed[a[i]]=i; } for(i=1;i<=m;i++) { cin>>l>>r; q[r].push_back(make_pair(l,i)); } for(i=1;i<=n;i++) { if(ed[a[i]]==i&&last[a[i]-1]+1<=st[a[i]]) T.update(n,last[a[i]-1]+1,st[a[i]],-1); if(ed[a[i]+1]<=i&&last[a[i]]+1<=min(st[a[i]+1],i)) T.update(n,last[a[i]]+1,min(st[a[i]+1],i),1); last[a[i]]=i; for(j=0;j<q[i].size();j++) ans[q[i][j].second]=T.getsum(q[i][j].first); } for(i=1;i<=m;i++) cout<<sum+ans[i]<<endl; return 0; }
luogu P3348 [ZJOI2016] 大森林
QOJ 8672. 排队
-
支持离线的函数复合板子。
- 插入-标记-回收 常用于解决函数复合问题,需要扫描线和支持全局进行函数操作的数据结构辅助维护。
- 分别将询问在左右端点各存储一次,然后从左往右进行扫描线。
- 插入
- 若当前扫到的
是某个询问的左端点 ,则将其对应的 放入数据结构中。
- 若当前扫到的
- 标记
- 对数据结构进行
的操作。
- 对数据结构进行
- 回收
- 若当前扫到的
是某个询问的右端点 ,则将其对应的 放入数据结构中的点的答案作为该询问的答案。 - 需要自顶向下下传所有标记。
- 若当前扫到的
- 为方便代码实现,记录
表示第 个询问对应的节点,并记录父亲节点。
-
函数操作和 [ABC389F] Rated Range 一样做即可,常数较大,多交几发就过了。
点击查看代码
int l[1000010],r[1000010],ans[1000010],it[1000010]; pair<int,int>ql[1000010],qr[1000010]; struct BST { int root,rt_sum; struct FHQ_Treap { int son[2],fa,val,rnd,cnt,siz,lazy; }tree[1000010]; #define lson(rt) (tree[rt].son[0]) #define rson(rt) (tree[rt].son[1]) #define fa(rt) (tree[rt].fa) BST() { rt_sum=0; srand(time(0)); } int build_rt(int val) { rt_sum++; lson(rt_sum)=rson(rt_sum)=fa(rt_sum)=tree[rt_sum].lazy=0; tree[rt_sum].val=val; tree[rt_sum].rnd=rand(); tree[rt_sum].cnt=tree[rt_sum].siz=1; return rt_sum; } void pushup(int rt) { tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt; fa(rt)=0; if(lson(rt)!=0) fa(lson(rt))=rt; if(rson(rt)!=0) fa(rson(rt))=rt; } void pushlazy(int rt,int lazy) { tree[rt].lazy+=lazy; tree[rt].val+=lazy; } void pushdown(int rt) { pushlazy(lson(rt),tree[rt].lazy); pushlazy(rson(rt),tree[rt].lazy); tree[rt].lazy=0; } void split(int rt,int val,int &x,int &y) { if(rt==0) { x=y=0; return; } pushdown(rt); if(tree[rt].val<=val) { x=rt; split(rson(rt),val,rson(x),y); } else { y=rt; split(lson(rt),val,x,lson(y)); } pushup(rt); } int merge(int rt1,int rt2) { if(rt1==0||rt2==0) return rt1+rt2; pushdown(rt1); pushdown(rt2); if(tree[rt1].rnd<tree[rt2].rnd) { rson(rt1)=merge(rson(rt1),rt2); pushup(rt1); return rt1; } else { lson(rt2)=merge(rt1,lson(rt2)); pushup(rt2); return rt2; } } int insert(int val) { int x,y; split(root,val,x,y); root=merge(merge(x,build_rt(val)),y); return rt_sum; } void update(int l,int r) { int x,y,rt; split(root,r,x,y); split(x,l-1,x,rt); pushlazy(rt,1); root=merge(merge(x,rt),y); } int query(int rt) { int ans=tree[rt].val; for(rt=fa(rt);rt!=0;rt=fa(rt)) ans+=tree[rt].lazy; return ans; } }T; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,m,x,y,i,j,k; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d%d",&l[i],&r[i]); for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); ql[i]=make_pair(x,i); qr[i]=make_pair(y,i); } sort(ql+1,ql+1+m); sort(qr+1,qr+1+m); for(i=j=k=1;i<=n;i++) { for(;ql[j].first==i;j++) it[ql[j].second]=T.insert(0); T.update(l[i],r[i]); for(;qr[k].first==i;k++) ans[qr[k].second]=T.query(it[qr[k].second]); } for(i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
luogu P9999 [Ynoi2000] tmostnrq
luogu P8264 [Ynoi Easy Round 2020] TEST_100
CF702F T-Shirts
CF1172F Nauuo and Bug
-
值域有交合并维护。点击查看代码
ll ans[200010]; int a[1000010],it[200010],p; pair<int,int>ql[200010],qr[200010]; struct BST { int root,rt_sum; struct FHQ_Treap { ll val,lazy; int son[2],fa,rnd,cnt,siz; }tree[200010]; #define lson(rt) (tree[rt].son[0]) #define rson(rt) (tree[rt].son[1]) #define fa(rt) (tree[rt].fa) BST() { rt_sum=0; srand(time(0)); } int build_rt(int val) { rt_sum++; lson(rt_sum)=rson(rt_sum)=fa(rt_sum)=tree[rt_sum].lazy=0; tree[rt_sum].val=val; tree[rt_sum].rnd=rand(); tree[rt_sum].cnt=tree[rt_sum].siz=1; return rt_sum; } void pushup(int rt) { tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt; fa(rt)=0; if(lson(rt)!=0) fa(lson(rt))=rt; if(rson(rt)!=0) fa(rson(rt))=rt; } void pushlazy(int rt,ll lazy) { tree[rt].lazy+=lazy; tree[rt].val+=lazy; } void pushdown(int rt) { pushlazy(lson(rt),tree[rt].lazy); pushlazy(rson(rt),tree[rt].lazy); tree[rt].lazy=0; } void split(int rt,ll val,int &x,int &y) { if(rt==0) { x=y=0; return; } pushdown(rt); if(tree[rt].val<=val) { x=rt; split(rson(rt),val,rson(x),y); } else { y=rt; split(lson(rt),val,x,lson(y)); } pushup(rt); } int merge(int rt1,int rt2) { if(rt1==0||rt2==0) return rt1+rt2; pushdown(rt1); pushdown(rt2); if(tree[rt1].rnd<tree[rt2].rnd) { rson(rt1)=merge(rson(rt1),rt2); pushup(rt1); return rt1; } else { lson(rt2)=merge(rt1,lson(rt2)); pushup(rt2); return rt2; } } int join(int rt1,int rt2) { if(rt1==0||rt2==0) return rt1+rt2; int rt=0; for(;rt2!=0;swap(rt1,rt2)) { int x=rt2; for(;lson(x)!=0;x=lson(x)) pushdown(x); split(rt1,tree[x].val,x,rt1); rt=merge(rt,x); } rt=merge(rt,rt1); return rt; } int insert(int val) { int x,y; split(root,val,x,y); root=merge(merge(x,build_rt(val)),y); return rt_sum; } void update(int val) { pushlazy(root,val); int x,y; split(root,p-1,x,y); pushlazy(y,-p); root=join(x,y); } ll query(int rt) { ll ans=tree[rt].val; for(rt=fa(rt);rt!=0;rt=fa(rt)) ans+=tree[rt].lazy; return ans; } }T; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,m,x,y,i,j,k; scanf("%lld%lld%lld",&n,&m,&p); for(i=1;i<=n;i++) scanf("%lld",&a[i]); for(i=1;i<=m;i++) { scanf("%lld%lld",&x,&y); ql[i]=make_pair(x,i); qr[i]=make_pair(y,i); } sort(ql+1,ql+1+m); sort(qr+1,qr+1+m); for(i=j=k=1;i<=n;i++) { for(;ql[j].first==i;j++) it[ql[j].second]=T.insert(0); T.update(a[i]); for(;qr[k].first==i;k++) ans[qr[k].second]=T.query(it[qr[k].second]); } for(i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }
luogu P10147 [Ynoi1999] 56TP
luogu P8337 [Ynoi2004] rsxc
luogu P9057 [Ynoi2004] rpfrdtzls
luogu P3316 [SDOI2014] 里面还是外面
luogu P11370 [Ynoi2024] 堕天作战/虚空处刑
luogu P11369 [Ynoi2024] 弥留之国的爱丽丝
luogu P11367 [Ynoi2024] 魔法少女网站第二部
luogu P10151 [Ynoi1999] SMV CC-64“蝰蛇”
luogu P10150 [Ynoi1999] TS-54
luogu P10028 [Ynoi2000] pri
luogu P9996 [Ynoi2000] hpi
luogu P9337 [Ynoi2001] 冷たい部屋、一人
luogu P9062 [Ynoi2002] Adaptive Hsearch&Lsearch
CF1100F Ivan and Burgers
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18671745,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
2024-02-02 2024初三年前集训测试2