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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

2021“MINIEYE杯”中国大学生算法设计超级联赛(1)zoto(二维数颜色)

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021“MINIEYE杯”中国大学生算法设计超级联赛(1)zoto(二维数颜色) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

zoto

Code1

樹狀數組套動態開點權值線段樹
效仿HH的項鏈,維護右端點,詢問需要排序

#include<bits/stdc++.h> using namespace std; template <class T=int> T rd() {T res=0;char ch=getchar();while(!isdigit(ch)) ch=getchar();while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res; } const int N=100010; int a[N],n,m,ans[N],last[N]; struct nodeq {int l,r,L,R,id;bool operator<(const nodeq& o)const{return r<o.r;} }q[N]; struct node {int l,r,v; }tree[N*200]; int rt[N],cnt; void update(int &u,int l,int r,int pos,int v) {if(!u) tree[u=++cnt]={0,0,0};tree[u].v+=v;if(l==r) return;int mid=l+r>>1;if(pos<=mid) update(tree[u].l,l,mid,pos,v);if(pos>mid) update(tree[u].r,mid+1,r,pos,v); } int query(int u,int l,int r,int L,int R) {if(!u) return 0;if(L<=l&&r<=R) return tree[u].v;int mid=l+r>>1;int v=0;if(L<=mid) v+=query(tree[u].l,l,mid,L,R);if(R>mid) v+=query(tree[u].r,mid+1,r,L,R);return v; } int lowbit(int x){return x&-x;} void add(int k,int pos,int v) {for(;k<=n;k+=lowbit(k)) update(rt[k],0,100000,pos,v); } int ask(int k,int L,int R) {int ans=0;for(;k;k-=lowbit(k)) ans+=query(rt[k],0,100000,L,R);return ans; }void init() {for(int i=1;i<=100000;i++) last[i]=0;for(int i=1;i<=n;i++) rt[i]=0;cnt=0;for(int i=0;i<=cnt;i++) tree[i].l=tree[i].r=tree[i].v=0; } int main() {int Tc=rd();while(Tc--){init();n=rd(),m=rd();for(int i=1;i<=n;i++) a[i]=rd();for(int i=1;i<=m;i++){int x0=rd(),y0=rd(),x1=rd(),y1=rd();q[i]={x0,x1,y0,y1,i};}sort(q+1,q+1+m);int k=1;for(int i=1;i<=m;i++){for(;k<=q[i].r;k++){int v=a[k];if(last[v]) add(last[v],v,-1);add(k,v,1);last[v]=k;}ans[q[i].id]=ask(q[i].r,q[i].L,q[i].R)-ask(q[i].l-1,q[i].L,q[i].R);}for(int i=1;i<=m;i++) printf("%d\n",ans[i]);} }

Code2

樹狀數組套動態開點權值線段樹
校dl的寫法,不需要對詢問進行排序

#include<bits/stdc++.h> using namespace std; template <class T=int> T rd() {T res=0;char ch=getchar();while(!isdigit(ch)) ch=getchar();while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res; } const int N=100010; int a[N],n,m,ans[N],last[N]; struct nodeq {int l,L,R,id; }; vector<nodeq> q[N]; struct node {int l,r,v; }tree[N*200]; int rt[N],cnt,lim; void update(int &u,int l,int r,int pos,int v) {if(!u) u=++cnt;tree[u].v+=v;if(l==r) return;int mid=l+r>>1;if(pos<=mid) update(tree[u].l,l,mid,pos,v);if(pos>mid) update(tree[u].r,mid+1,r,pos,v);//tree[u].v=tree[tree[u].l].v+tree[tree[u].r].v; } int query(int u,int l,int r,int L,int R) {if(!u) return 0;if(L<=l&&r<=R) return tree[u].v;int mid=l+r>>1;int v=0;if(L<=mid) v+=query(tree[u].l,l,mid,L,R);if(R>mid) v+=query(tree[u].r,mid+1,r,L,R);return v; } int lowbit(int x){return x&-x;} void add(int k,int pos,int v) {for(;k<=n;k+=lowbit(k)) update(rt[k],0,lim,pos,v); } int ask(int k,int L,int R) {int ans=0;for(;k;k-=lowbit(k)) ans+=query(rt[k],0,lim,L,R);return ans; } void init() {for(int i=0;i<=lim;i++) last[i]=0;for(int i=0;i<=n;i++) rt[i]=0;for(int i=0;i<=cnt;i++) tree[i].l=tree[i].r=tree[i].v=0;cnt=0;for(int i=0;i<=n;i++) q[i].clear(); } int main() {int Tc=rd();while(Tc--){init();n=rd(),m=rd();for(int i=1;i<=n;i++) a[i]=rd();lim=*max_element(a+1,a+1+n);for(int i=1;i<=m;i++){int x0=rd(),y0=rd(),x1=rd(),y1=rd();q[x1].push_back({x0,y0,y1,i});}for(int i=1;i<=n;i++){if(last[a[i]]) add(last[a[i]],a[i],-1);add(i,a[i],1);last[a[i]]=i;for(auto t:q[i])ans[t.id]=ask(i,t.L,t.R)-ask(t.l-1,t.L,t.R);}for(int i=1;i<=m;i++) printf("%d\n",ans[i]);} }

Code3

std寫法

首先來看一個子問題:給一個數組,初始所有位置全是0,每次單點加一或減一,詢問區間有多少個位置不為0。也許你很快會給出一個修改O(logn)查詢O(logn)的優秀做法。那么如果強制規定修改O(1),查詢能做到什么效率?我們去考慮分塊,維護兩個數組num[i]和sum[i]分別維護第i位置上的值,以及第i塊內的值不為0的位置個數。那么每次單點修改只需要修改num[i]和sum[i/block_size]兩個位置的值,然后查詢的時候需要O(sqrtn)效率的去查詢區間所覆蓋的完整塊的值以及區間兩端散塊的值(散塊值可以沒有)。這顯然是一個修改O(1),查詢O(sqrtn)的做法。
然后考慮這個題,我們發現可以用莫隊去維護詢問的區間,即x坐標。y(fx)維度單獨拎出來就變成了上述子問題。我們會神奇的發現,這樣的復雜度是:O(nsqrt(n)1+m1sqrt(n))的,莫隊單次修改時O(sqrtn)的復雜度遇上了值域上O(1)的修改,莫隊單次查詢時O(1)的復雜度遇上了值域查詢時O(sqrt(n))的復雜度。

#include<bits/stdc++.h>using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;char ch=getchar();while(!isdigit(ch)) ch=getchar();while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res; } const int N=100010; int a[N],n,m;int b[N],sz; struct nodeq {int l,r,L,R,id;bool operator<(const nodeq&o)const{if(b[l]==b[o.l]){if(b[l]&1)return r<o.r;elsereturn r>o.r;}return b[l]<b[o.l];} }q[N]; int num[N],sum[N],ans[N]; void add(int k){if(++num[k]==1) sum[b[k]]++;} void sub(int k){if(--num[k]==0) sum[b[k]]--;} int query(int k) {int res=0;for(int i=1;i<b[k];i++) res+=sum[i];for(int i=(b[k]-1)*sz+1;i<=k;i++) res+=(num[i]>=1);return res; } int main() {int Tc=rd();while(Tc--){n=rd(),m=rd(),sz=313;for(int i=1;i<=n;i++) a[i]=rd();for(int i=1;i<=n;i++) sum[i]=num[i]=0;for(int i=1;i<=n;i++) b[i]=(i-1)/sz+1;for(int i=1;i<=m;i++){int x0=rd(),y0=rd(),x1=rd(),y1=rd();q[i]={x0,x1,y0,y1,i};}sort(q+1,q+1+m);int l=1,r=0;for(int i=1;i<=m;i++){while(l<q[i].l) sub(a[l++]);while(l>q[i].l) add(a[--l]);while(r<q[i].r) add(a[++r]);while(r>q[i].r) sub(a[r--]);ans[q[i].id]=query(q[i].R)-query(q[i].L-1);}for(int i=1;i<=m;i++) printf("%d\n",ans[i]);} }

Code4

把種類查詢轉換偏序查詢的常規操作:指向上一個出現的位置當且僅當上一次出現的位置在區間外面時計算貢獻

cdq分治+bit
對于每個詢問的右端點也看作一個時間軸,如果該點可能對詢問產生貢獻,那么下一個這個點的橫坐標嚴格大于詢問右端點。
a1≤a1b1≤b2c1>c2a_1\leq a_1\\ b_1\leq b_2 \\c_1>c_2a1?a1?b1?b2?c1?>c2?
cdq分治轉化為平面二維數點,然后差分+bit即可統計。


對于每個詢問的左端點也看作一個時間軸,如果該點可能對詢問產生貢獻,那么前一個這個點的橫坐標嚴格小于詢問左端點。

本質都種類→\to偏序

#include<bits/stdc++.h> using namespace std; template <class T=int> T rd() {T res=0;char ch=getchar();while(!isdigit(ch)) ch=getchar();while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res; } const int N=100010; int a[N],n,m,ans[N],last[N]; int ne[N],pos[N]; struct nodeq {int op;int a,b,c;int fg,id; }q[N<<4]; int fw[N]; int lowbit(int x){return x&-x;} void update(int k,int v){for(;k<=n+1;k+=lowbit(k)) fw[k]+=v;} int qsum(int k){int v=0;for(;k;k-=lowbit(k)) v+=fw[k];return v;}void solve(int l,int r) {if(l>=r) return;int mid=l+r>>1;solve(l,mid),solve(mid+1,r);int i=l;for(int j=mid+1;j<=r;j++){while(i<=mid&&q[i].b<=q[j].b) {if(q[i].op==0) update(q[i].c,1);i++;}if(q[j].op==1) ans[q[j].id]+=q[j].fg*(qsum(n+1)-qsum(q[j].c));}while(i>l) {--i;if(q[i].op==0) update(q[i].c,-1);}inplace_merge(q+l,q+mid+1,q+r+1,[](const nodeq&x,const nodeq&y){return x.b<y.b||x.b==y.b&&x.a<y.a;}); } int main() {int Tc=rd();while(Tc--){n=rd(),m=rd();for(int i=1;i<=n;i++) a[i]=rd();for(int i=1;i<=m;i++) ans[i]=0;for(int i=0;i<=100000;i++) pos[a[i]]=n+1;for(int i=n;i>=1;i--) {ne[i]=pos[a[i]];pos[a[i]]=i;}int cnt=0;for(int i=1;i<=n;i++) q[++cnt]={0,i,a[i],ne[i]};for(int i=1;i<=m;i++){int x0=rd(),y0=rd(),x1=rd(),y1=rd();q[++cnt]={1,x0-1,y0-1,x1,1,i};q[++cnt]={1,x0-1,y1,x1,-1,i};q[++cnt]={1,x1,y0-1,x1,-1,i};q[++cnt]={1,x1,y1,x1,1,i};}sort(q+1,q+1+cnt,[](const nodeq&x,const nodeq&y){return x.a<y.a||x.a==y.a&&x.b<y.b;});solve(1,cnt);for(int i=1;i<=m;i++) printf("%d\n",ans[i]);} }

Code5

和Code4基本一樣

#include<bits/stdc++.h> using namespace std; template <class T=int> T rd() {T res=0;char ch=getchar();while(!isdigit(ch)) ch=getchar();while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res; } const int N=100010; int a[N],n,m,ans[N]; int last[N],pos[N]; struct nodeq {int op;int a,b,c;int fg,id; }q[N<<4]; int fw[N]; int lowbit(int x){return x&-x;} void update(int k,int v){if(!k) return fw[k]+=v,void();for(;k<=n;k+=lowbit(k)) fw[k]+=v;} int qsum(int k){int v=fw[0];for(;k;k-=lowbit(k)) v+=fw[k];return v;}void solve(int l,int r) {if(l>=r) return;int mid=l+r>>1;solve(l,mid),solve(mid+1,r);int i=l;for(int j=mid+1;j<=r;j++){while(i<=mid&&q[i].b<=q[j].b) {if(q[i].op==0) update(q[i].c,1);i++;}if(q[j].op==1) ans[q[j].id]+=q[j].fg*qsum(q[j].c);}while(i>l) {--i;if(q[i].op==0) update(q[i].c,-1);}inplace_merge(q+l,q+mid+1,q+r+1,[](const nodeq&x,const nodeq&y){return x.b<y.b||x.b==y.b&&x.a<y.a;}); } int main() {int Tc=rd();while(Tc--){n=rd(),m=rd();for(int i=1;i<=n;i++) a[i]=rd();for(int i=1;i<=m;i++) ans[i]=0;for(int i=0;i<=100000;i++) pos[a[i]]=0;for(int i=1;i<=n;i++) {last[i]=pos[a[i]];pos[a[i]]=i;}int cnt=0;for(int i=1;i<=n;i++) q[++cnt]={0,i,a[i],last[i]};for(int i=1;i<=m;i++){int x0=rd(),y0=rd(),x1=rd(),y1=rd();q[++cnt]={1,x0-1,y0-1,x0-1,1,i};q[++cnt]={1,x0-1,y1,x0-1,-1,i};q[++cnt]={1,x1,y0-1,x0-1,-1,i};q[++cnt]={1,x1,y1,x0-1,1,i};}sort(q+1,q+1+cnt,[](const nodeq&x,const nodeq&y){return x.a<y.a||x.a==y.a&&x.b<y.b;});solve(1,cnt);for(int i=1;i<=m;i++) printf("%d\n",ans[i]);} }

總結

以上是生活随笔為你收集整理的2021“MINIEYE杯”中国大学生算法设计超级联赛(1)zoto(二维数颜色)的全部內容,希望文章能夠幫你解決所遇到的問題。

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