日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第四章 高级数据结构

發布時間:2025/3/20 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第四章 高级数据结构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 并查集
    • 1250. 格子游戲【并查集判環】
    • 1252. 搭配購買【并查集 + 01背包】
    • 237. 程序自動分析【并查集的擴展】
    • 239. 奇偶游戲【不會】
    • 238. 銀河英雄傳說【維護距離的并查集】
  • 樹狀數組
    • 241. 樓蘭圖騰【樹狀數組的基本應用】
    • 242. 一個簡單的整數問題【區間修改 / 單點查詢】
    • 243. 一個簡單的整數問題2【區間修改 / 區間查詢】
    • 244. 謎一樣的牛【快速求排名擴展】
  • 線段樹
    • 1275. 最大數【線段樹 / 維護區間最大值】
    • 245. 你能回答這些問題嗎【單點修改 求區間的最大連續子段和】
    • 243. 一個簡單的整數問題2【區間修改 / 區間查詢】
    • 1277. 維護序列【區間乘/加 區間查詢】
  • 可持續化數據結構
    • 255. 第K小數【可持續化線段樹 / 主席樹】
  • AC自動機
    • 1282. 搜索關鍵詞
    • 1285. 單詞

并查集

并查集的基本操作:

  • 合并兩個集合
  • 查詢某個元素的祖宗結點

并查集的基本應用擴展

  • 記錄每個集合的大小(綁定到根節點)
  • 記錄每個點到根節點的距離。(綁定到每個元素上)

1250. 格子游戲【并查集判環】


https://www.acwing.com/problem/content/description/1252/
如果合并之前,這兩元素已經在集合中,那么說明有環。
1250. 格子游戲【并查集】

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int p[N],n,m; int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } int get(int x,int y) {return x*n+y;} int main(void) {cin>>n>>m;for(int i=0;i<n*n;i++) p[i]=i;for(int i=1;i<=m;i++){int x,y;char op; cin>>x>>y>>op;x--,y--;int a=get(x,y),b;if(op=='R') b=get(x,y+1);else b=get(x+1,y);if(find(a)==find(b)){cout<<i;return 0;}p[find(a)]=find(b);}puts("draw");return 0; }

1252. 搭配購買【并查集 + 01背包】


https://www.acwing.com/problem/content/description/1254/
1252. 搭配購買【并查集 + 01背包】

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int w[N],v[N],p[N],n,m,sum,f[N]; int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } int main(void) {cin>>n>>m>>sum;for(int i=1;i<=n;i++) p[i]=i;for(int i=1;i<=n;i++) cin>>v[i]>>w[i];for(int i=1;i<=m;i++){int a,b; cin>>a>>b;if(find(a)!=find(b)){w[find(a)]+=w[find(b)];v[find(a)]+=v[find(b)];p[find(b)]=find(a);}}for(int i=1;i<=n;i++){if(p[find(i)]==i)//說明是一個根節點{for(int j=sum;j>=v[i];j--){f[j]=max(f[j],f[j-v[i]]+w[i]);}}}cout<<f[sum];return 0; }

237. 程序自動分析【并查集的擴展】


https://www.acwing.com/problem/content/description/239/
237. 程序自動分析【并查集】

#include<bits/stdc++.h> using namespace std; const int N=1e5*3+10; struct node {int a,b,c;}; int p[N],t,n,idx; unordered_map<int,int>mp; int get(int x)//離散化 {if(mp.count(x)==0) mp[x]=++idx;return mp[x]; } void init(){mp.clear(),idx=0;}//初始化 int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } int main(void) {cin>>t;while(t--){init();cin>>n;vector<node>ve;for(int i=0;i<n;i++){int a,b,c; cin>>a>>b>>c;ve.push_back({get(a),get(b),c});}for(int i=1;i<=idx;i++) p[i]=i;for(int i=0;i<ve.size();i++)if(ve[i].c==1&&find(ve[i].a)!=find(ve[i].b)) p[find(ve[i].b)]=find(ve[i].a);bool flag=true;for(int i=0;i<ve.size();i++)if(!ve[i].c&&find(ve[i].a)==find(ve[i].b)) flag=false;if(flag) puts("YES");else puts("NO");}return 0; }

239. 奇偶游戲【不會】



https://www.acwing.com/problem/content/241/

238. 銀河英雄傳說【維護距離的并查集】


https://www.acwing.com/problem/content/240/
238. 銀河英雄傳說【邊帶權的并查集】

#include<bits/stdc++.h> using namespace std; const int N=1e5*3+10; int p[N],cnt[N],d[N],n; int find(int x) {if(x!=p[x]){int root=find(p[x]);d[x]+=d[p[x]];p[x]=root;}return p[x]; } int main(void) {for(int i=1;i<N;i++) p[i]=i,cnt[i]=1;cin>>n;while(n--){string op;int a,b; cin>>op>>a>>b;if(op=="M"){int pa=find(a),pb=find(b);d[pa]=cnt[pb];cnt[pb]+=cnt[pa];p[pa]=pb;}else{int pa=find(a),pb=find(b);if(pa==pb) cout<<max(0,abs(d[a]-d[b])-1)<<endl;else cout<<-1<<endl;}}return 0; }

樹狀數組

241. 樓蘭圖騰【樹狀數組的基本應用】


https://www.acwing.com/problem/content/243/

#include<bits/stdc++.h> using namespace std; const int N=1e5*2+10; typedef long long int LL; LL up[N],down[N],a[N],tr[N],n; int lowbit(int x) {return x&(-x);} int add(int x,int v) {for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;} LL query(int x) {LL sum=0;for(int i=x;i;i-=lowbit(i)) sum+=tr[i];return sum; } int main(void) {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=n;i>=1;i--){up[i]=query(n)-query(a[i]);down[i]=query(a[i]-1);add(a[i],1);}memset(tr,0,sizeof tr);long long int ans1=0,ans2=0;for(int i=1;i<=n;i++){ans1+=(query(n)-query(a[i]))*up[i];ans2+=query(a[i]-1)*down[i];add(a[i],1);}cout<<ans1<<" "<<ans2<<endl;return 0; }

242. 一個簡單的整數問題【區間修改 / 單點查詢】


https://www.acwing.com/problem/content/description/248/

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int tr[N],a[N],n,m; int lowbit(int x){return x&(-x);} int add(int x,int v){for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;} int query(int x) {int sum=0;for(int i=x;i;i-=lowbit(i)) sum+=tr[i];return sum; } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>a[i],add(i,a[i]-a[i-1]);while(m--){string op; cin>>op;if(op=="C"){int l,r,c; cin>>l>>r>>c;add(l,c),add(r+1,-c);}else {int x; cin>>x;cout<<query(x)<<endl;}}return 0; }

243. 一個簡單的整數問題2【區間修改 / 區間查詢】


https://www.acwing.com/problem/content/description/244/
詳細題解

#include<bits/stdc++.h> using namespace std; typedef long long int LL; const int N=1e5+10; LL tr1[N],tr2[N],a[N],n,m; LL lowbit(LL x){return x&(-x);} LL add(LL tr[],LL x,LL v){for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;} LL query(LL tr[],LL x) {LL sum=0;for(int i=x;i;i-=lowbit(i)) sum+=tr[i];return sum; } LL sum(LL x) {return query(tr1,x)*(x+1)-query(tr2,x); } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];LL b=a[i]-a[i-1];add(tr1,i,b);add(tr2,i,i*b);}while(m--){string op; cin>>op;if(op=="C"){LL l,r,d; cin>>l>>r>>d;add(tr1,l,d),add(tr1,r+1,-d);add(tr2,l,l*d),add(tr2,r+1,-d*(r+1));}else {LL l,r; cin>>l>>r;cout<<sum(r)-sum(l-1)<<endl;}}return 0; }

244. 謎一樣的牛【快速求排名擴展】


https://www.acwing.com/problem/content/245/
詳細題解

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int tr[N],a[N],b[N],n; int lowbit(int x) {return x&(-x);} int add(int x,int v) {for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;} int query(int x) {int sum=0;for(int i=x;i;i-=lowbit(i)) sum+=tr[i];return sum; } int main(void) {cin>>n;for(int i=2;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) add(i,1);for(int i=n;i>=1;i--){int x=a[i]+1;int l=1,r=n;while(l<r){int mid=l+r>>1;if(query(mid)>=x) r=mid;else l=mid+1;}b[i]=l;add(l,-1);}for(int i=1;i<=n;i++) cout<<b[i]<<endl;return 0; }

線段樹


上圖摘自: https://www.acwing.com/blog/content/372/
線段樹常用的操作:

  • pushup 由子節點的信息,來計算父節點的信息
  • pushdown 由父節點更新子節點節點信息 lazytag(懶標記)
  • build 由區間建立線段樹
  • modify 修改某一個點(easy)或者區間(hard)
  • query 查詢某一端區間信息

線段樹常見的應用場景:

  • 單點修改
  • 區間查詢
  • 區間修改

相關的文章:https://www.cnblogs.com/jason2003/p/9676729.html
詳細理解線段樹

1275. 最大數【線段樹 / 維護區間最大值】


https://www.acwing.com/problem/content/description/1277/

#include<bits/stdc++.h> using namespace std; typedef long long int LL; const int N=1e5*2+10; int m,p; struct node{int l,r,v;}tr[N*4];//[l,r]區間中的最大值 void pushup(int u)//由子節點的信息,來計算父節點的信息 {tr[u].v=max(tr[u<<1].v,tr[u<<1 | 1 ].v); } void build(int u,int l,int r)//建樹,u是根節點,l是左邊界,r是右邊界 {tr[u]={l,r};if(l==r) return;//葉子結點 int mid=l+r>>1;build(u<<1,l,mid),build(u<<1|1,mid+1,r); } int query(int u,int l,int r)//u是根節點,查詢[l,r]區間 {if(tr[u].l>=l&&tr[u].r<=r) return tr[u].v;//如果這個區間被完全包括在目標區間[l,r]里面,直接返回這個區間的值int mid=tr[u].l+tr[u].r>>1;int v=0;if(l<=mid) v=query(u<<1,l,r);//如果這個區間的左兒子和目標區間又交集,那么搜索左兒子if(r>mid) v=max(v,query(u<<1|1,l,r));如果這個區間的右兒子和目標區間又交集,那么搜索右兒子return v; } void modify(int u,int x,int v)//u是根,x是位置,v是添加的數 {if(tr[u].l==x&&tr[u].r==x) tr[u].v=v;else{int mid=tr[u].l+tr[u].r>>1;if(x<=mid) modify(u<<1,x,v);else modify(u<<1|1,x,v);pushup(u);} } int main(void) {int n=0,last=0;scanf("%d%d",&m,&p);build(1,1,m);int x;string op;while(m--){cin>>op>>x;if(op=="Q"){last=query(1,n-x+1,n);cout<<last<<endl;}else {modify(1,n+1,(1ll*last+x)%p);n++;}}return 0; }

245. 你能回答這些問題嗎【單點修改 求區間的最大連續子段和】


https://www.acwing.com/problem/content/246/

#include<bits/stdc++.h> using namespace std; const int N=1e5*5+10; int n,m; int w[N]; struct node {int l,r;int sum,lmax,rmax,tmax;//sum: 區間和//tmax:整個區間的最大子段和//lmax:從左端點起的向右的最大子段和//rmax:從右端點起的向左的最大子段和 }tr[N*4]; void pushup(node &u,node &l,node &r) {u.sum=l.sum+r.sum;u.lmax=max(l.lmax,l.sum+r.lmax);u.rmax=max(r.rmax,r.sum+l.rmax);u.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax); } void pushup(int u) {pushup(tr[u],tr[u<<1],tr[u<<1 | 1]); } void build(int u,int l,int r) {if(l==r) tr[u]={l,r,w[r],w[r],w[r],w[r]};else{tr[u]={l,r};int mid=l+r>>1;build(u<<1,l,mid),build(u<<1|1,mid+1,r);pushup(u);} } void modify(int u,int x,int v) {if(tr[u].l==x&&tr[u].r==x) tr[u]={x,x,v,v,v,v};else{int mid=tr[u].l+tr[u].r>>1;if(x<=mid) modify(u<<1,x,v);else modify(u<<1|1,x,v);pushup(u);} } node query(int u,int l,int r) {if(tr[u].l>=l&&tr[u].r<=r) return tr[u];else{int mid=tr[u].l+tr[u].r>>1;if(r<=mid) return query(u<<1,l,r);else if(l>mid) return query(u<<1|1,l,r);else{auto left=query(u<<1,l,r);auto right=query(u<<1|1,l,r);node res;pushup(res,left,right);return res; }} } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>w[i];build(1,1,n);int k,x,y;while(m--){cin>>k>>x>>y;if(k==1){if(x>y) swap(x,y);printf("%d\n",query(1,x,y).tmax);}else modify(1,x,y);}return 0; }

243. 一個簡單的整數問題2【區間修改 / 區間查詢】


https://www.acwing.com/problem/content/description/244/

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; typedef long long int LL; int n,m; int w[N]; struct node {int l,r;LL sum,add; }tr[N*4]; void pushup(int u) {tr[u].sum=tr[u<<1].sum+tr[u<<1 | 1].sum; } void pushdown(int u) {auto &root=tr[u],&left=tr[u<<1],&right=tr[u<<1 | 1];if(root.add){left.add+=root.add,left.sum+=(LL)(left.r-left.l+1)*root.add;right.add+=root.add,right.sum+=(LL)(right.r-right.l+1)*root.add;root.add=0;} } void build(int u,int l,int r) {if(l==r) tr[u]={l,r,w[r],0};else{tr[u]={l,r};int mid=l+r>>1;build(u<<1,l,mid),build(u<<1 | 1,mid+1,r);pushup(u);} } void modify(int u,int l,int r,int d) {if(tr[u].l>=l&&tr[u].r<=r){tr[u].sum+=(LL)(tr[u].r-tr[u].l+1)*d;tr[u].add+=d;}else//一定分裂 {pushdown(u);int mid=tr[u].l+tr[u].r>>1;if(l<=mid) modify(u<<1,l,r,d);if(r>mid) modify(u<<1 | 1,l,r,d);pushup(u);} } LL query(int u,int l,int r) {if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;pushdown(u);int mid=tr[u].l+tr[u].r>>1;LL sum=0;if(l<=mid) sum=query(u<<1,l,r);if(r>mid) sum+=query(u<<1 | 1,l,r);return sum; } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>w[i];build(1,1,n);while(m--){string op; cin>>op;if(op=="Q"){int l,r; cin>>l>>r;cout<<query(1,l,r)<<endl;}else{int l,r,d; cin>>l>>r>>d;modify(1,l,r,d);}}return 0; }

1277. 維護序列【區間乘/加 區間查詢】


https://www.acwing.com/problem/content/1279/

#include<bits/stdc++.h> using namespace std; typedef long long int LL; const int N=1e5+10; int n,m,p; int w[N]; struct node {int l,r;int sum,add,mul; }tr[N*4]; void pushup(int u) {tr[u].sum=(tr[u<<1].sum+tr[u<<1 | 1].sum)%p; } void eval(node &t,int add,int mul) {t.sum=((LL)t.sum*mul+(LL)(t.r-t.l+1)*add)%p;t.mul=(LL)t.mul*mul%p;t.add=((LL)t.add*mul+add)%p; } void pushdown(int u) {eval(tr[u<<1],tr[u].add,tr[u].mul);eval(tr[u<<1 | 1],tr[u].add,tr[u].mul);tr[u].add=0,tr[u].mul=1; } void build(int u,int l,int r) {if(l==r) tr[u]={l,r,w[r],0,1};else{tr[u]={l,r,0,0,1};int mid=l+r>>1;build(u<<1,l,mid),build(u<<1|1,mid+1,r);pushup(u);} } void modify(int u,int l,int r,int add,int mul) {if(tr[u].l>=l&&tr[u].r<=r) eval(tr[u],add,mul);else{pushdown(u);int mid=tr[u].l+tr[u].r>>1;if(l<=mid) modify(u<<1,l,r,add,mul);if(r>mid) modify(u<<1|1,l,r,add,mul);pushup(u);} } int query(int u,int l,int r) {if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;pushdown(u);int mid=tr[u].l+tr[u].r>>1;int sum=0;if(l<=mid) sum=query(u<<1,l,r);if(r>mid) sum=(sum+query( u<< 1 | 1 ,l,r) )%p;return sum; } int main(void) {cin>>n>>p;for(int i=1;i<=n;i++) cin>>w[i];build(1,1,n);cin>>m;while(m--){int op; cin>>op;if(op==1)//區間乘法{int l,r,d; cin>>l>>r>>d;modify(1,l,r,0,d);}else if(op==2)//區間加{int l,r,d; cin>>l>>r>>d;modify(1,l,r,d,1);}else//區間查詢{int l,r; cin>>l>>r;cout<<query(1,l,r)<<endl;}}return 0; }

可持續化數據結構

255. 第K小數【可持續化線段樹 / 主席樹】


https://www.acwing.com/problem/content/257/

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int n,m; int a[N]; vector<int>nums; struct Node {int l,r;int cnt; }tr[N*4+N*17]; int root[N],idx; int find(int x)//離散化 {return lower_bound(nums.begin(),nums.end(),x)-nums.begin(); } int build(int l,int r) {int p=++idx;if(l==r) return p;int mid=l+r>>1;tr[p].l=build(l,mid),tr[p].r=build(mid+1,r);return p; } int insert(int p,int l,int r,int x) {int q=++idx;tr[q]=tr[p];if(l==r){tr[q].cnt++;return q;}int mid=l+r>>1;if(x<=mid) tr[q].l=insert(tr[p].l,l,mid,x);else tr[q].r=insert(tr[p].r,mid+1,r,x);tr[q].cnt=tr[tr[q].l].cnt+tr[tr[q].r].cnt;return q; } int query(int q,int p,int l,int r,int k) {if(l==r) return r;int cnt=tr[tr[q].l].cnt-tr[tr[p].l].cnt;int mid=l+r>>1;if(k<=cnt) return query(tr[q].l,tr[p].l,l,mid,k);else return query(tr[q].r,tr[p].r,mid+1,r,k-cnt); } int main(void) {scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i]);nums.push_back(a[i]);}sort(nums.begin(),nums.end());//離散化nums.erase(unique(nums.begin(),nums.end()),nums.end());root[0]=build(0,nums.size()-1);for(int i=1;i<=n;i++)root[i]=insert(root[i-1],0,nums.size()-1,find(a[i]));while(m--){int l,r,k; scanf("%d%d%d",&l,&r,&k);printf("%d\n",nums[query(root[r],root[l-1],0,nums.size()-1,k)]);}return 0; }

AC自動機

1282. 搜索關鍵詞


https://www.acwing.com/problem/content/description/1284/

#include<bits/stdc++.h> using namespace std; const int N=1e4+10,S=55,M=1e6+10; int n; int tr[N*S][26],cnt[N*S],idx; char str[M]; int q[N*S],ne[N*S]; void insert() {int p=0;for(int i=0;str[i];i++){int t=str[i]-'a';if(!tr[p][t]) tr[p][t]=++idx;p=tr[p][t];}cnt[p]++; } void build() {int hh=0,tt=-1;for(int i=0;i<26;i++)if(tr[0][i]) q[++tt]=tr[0][i];while(hh<=tt){int t=q[hh++];for(int i=0;i<26;i++){int p=tr[t][i];if(!p) tr[t][i]=tr[ne[t]][i];else{ne[p]=tr[ne[t]][i];q[++tt]=p;}}} } int main(void) {int t; cin>>t;while(t--){memset(tr,0,sizeof tr);memset(cnt,0,sizeof cnt);memset(ne,0,sizeof ne);idx=0;cin>>n;for(int i=0;i<n;i++){scanf("%s",str);insert();}build();scanf("%s",str);int res=0;for(int i=0,j=0;str[i];i++){int t=str[i]-'a';j=tr[j][t];int p=j;while(p){res+=cnt[p];cnt[p]=0;p=ne[p];}}printf("%d\n",res);}return 0; }

1285. 單詞


https://www.acwing.com/problem/content/1287/

#include<bits/stdc++.h> using namespace std; const int N=1e6+10; int n; int tr[N][26],f[N],idx; int q[N],ne[N]; char str[N]; int id[210]; void insert(int x) {int p=0;for(int i=0;str[i];i++){int t=str[i]-'a';if(!tr[p][t]) tr[p][t]=++idx;p=tr[p][t];f[p]++;}id[x]=p; } void build() {int hh=0,tt=-1;for(int i=0;i<26;i++)if(tr[0][i]) q[++tt]=tr[0][i];while(hh<=tt){int t=q[hh++];for(int i=0;i<26;i++){int &p=tr[t][i];if(!p) p=tr[ne[t]][i];else {ne[p]=tr[ne[t]][i];q[++tt]=p;}}} } int main(void) {scanf("%d",&n);for(int i=0;i<n;i++){scanf("%s",str);insert(i);}build();for(int i=idx-1;i>=0;i--) f[ne[q[i]]]+=f[q[i]];for(int i=0;i<n;i++) printf("%d\n",f[id[i]]);return 0; }

總結

以上是生活随笔為你收集整理的第四章 高级数据结构的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。