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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

2021牛客多校2 - WeChat Walk(分块)

發布時間:2024/4/11 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021牛客多校2 - WeChat Walk(分块) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出 nnn 個人,再給出 mmm 對好友關系,每個人都有一個朋友圈用來顯示微信步數。現在有 qqq 次操作,每次操作會讓某個人的微信步數增加,問最后對于每個人來說,在自己朋友圈內獲得冠軍的時間

題目分析:暴力去想,因為每次都是單點更新,所以只會影響當前點和周圍相鄰點的朋友圈,但是這樣會被菊花圖卡成 O(n2)O(n^2)O(n2)

不難往分塊上去想,所以直接掛官方題解:


按照題解這樣實現細節很多,感覺如果沒有參考別人代碼的話很難寫出來。但是同時題解將本題需要思考的一些突破點都說出來了,我們嘗試換種方法繼續思考。

首先比較關鍵的幾個點是:

  • 要按照度數將點分成“小點”和“大點”,并且“大點”的個數一定小于 n\sqrt{n}n?
  • 對于“小點”可以暴力,對于“大點”需要借助“小點”維護某些東西加速更新、統計答案
  • 有效步數,即權值很小,可以按照權值排序
  • 到此為止簡單說一下另一種解法,在原圖的基礎上,增加一個新圖:big[x]big[x]big[x] 代表點 xxx 所能到達的所有“大點”,新圖一定滿足,每個點的度數都不超過 n\sqrt{n}n?

    將所有的詢問先線性維護 val[x]val[x]val[x] 代表每個點在某次詢問后的步數,因為在經過某次詢問后,修改點 xxx 后,會出現兩種情況:

  • xxx 在自己的朋友圈內變成了冠軍
  • xxx 相鄰的點 yyyxxx 擠下了冠軍
  • 所以將所有詢問按照每次更新后的 val[x]val[x]val[x] 排個序,然后從后向前處理。因為如果正著處理的話,本質上就和官方題解一樣了,倒著的話可以實現起來少處理一點細節。

    我們維護三個變量:

  • first_last[i]:點 iii 最后一次訪問時間(第幾次詢問)
  • second_last[i]:點 iii 倒數第二次訪問時間(即first_last[i]的上一次)
  • big_mmin[i]:“大點” iii 周圍所有點,最近一次當冠軍時間的最小值
  • 每次遍歷到一個詢問時,自然需要更新一下兩個 last,同時需要對相鄰的“大點”更新一下其 big_mmin 變量。同時后續需要對該詢問統計答案,即“冠軍時長”,這里需要分兩種情況:

  • 如果是“小點”的話,直接暴力遍歷相鄰的點,統計一下最后一次訪問時間的最小值即可。因為我們是倒著遍歷的,假如相鄰點訪問時間比當前時間還早的話,說明當前點當不了冠軍,反之就可以計算出當前點當冠軍的時間區間了
  • 如果是“大點”的話,可以直接通過上面維護的 big_mmin 來計算
  • 代碼:
    正著遍歷(官方題解):

    // Problem: WeChat Walk // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/11253/L // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; int u[N],v[N],du[N],big[N],ans[N],tim[N],val[N],limit[N],cnt,sq; vector<int>C[510][10010];//C[i][j]:Poing i has the nums of small points which (weight=j) vector<int>node[N]; void add(int u,int v) {node[u].push_back(v); } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m,q;read(n),read(m),read(q);for(int i=1;i<=m;i++) {read(u[i]),read(v[i]);du[u[i]]++,du[v[i]]++;}sq=sqrt(n);for(int i=1;i<=n;i++) {if(du[i]>=sq) {big[i]=++cnt;}}for(int i=1;i<=m;i++) {if(!big[u[i]]) {//small -> alladd(u[i],v[i]);} else if(big[v[i]]) {//big -> only bigadd(u[i],v[i]);}swap(u[i],v[i]);if(!big[u[i]]) {add(u[i],v[i]);} else if(big[v[i]]) {add(u[i],v[i]);}}for(int i=1;i<=q;i++) {int u,w;read(u),read(w);if(!big[u]) {//small update allval[u]+=w;int mmax=0;for(auto v:node[u]) {mmax=max(mmax,val[v]);limit[v]=max(limit[v],val[u]);if(tim[v]&&val[u]>=val[v]) {ans[v]+=i-tim[v];tim[v]=0;}}if(!tim[u]&&val[u]>mmax) {tim[u]=i;}if(tim[u]) {for(auto v:node[u]) {if(big[v]) {C[big[v]][val[u]].push_back(u);}}}} else {//bigval[u]+=w;int mmax=0;for(auto v:node[u]) {//bigmmax=max(mmax,val[v]);if(tim[v]&&val[u]>=val[v]) {ans[v]+=i-tim[v];tim[v]=0;}}//smallfor(int j=val[u]-w+1;j<=val[u];j++) {//some small update winner to loserfor(auto v:C[big[u]][j]) {if(tim[v]&&val[u]>=val[v]) {ans[v]+=i-tim[v];tim[v]=0;}}}if(!tim[u]&&val[u]>max(mmax,limit[u])) {tim[u]=i;}}}for(int i=1;i<=n;i++) {if(tim[i]) {ans[i]+=q-tim[i];}printf("%d\n",ans[i]);}return 0; }

    倒著遍歷(民間題解):

    // Problem: WeChat Walk // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/11253/L // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; vector<int>node[N],big[N]; vector<pair<int,int>>t[N]; int sq,val[N],ans[N],first_last[N],second_last[N],big_mmin[N]; int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m,q;read(n),read(m),read(q);sq=sqrt(n);while(m--) {int u,v;read(u),read(v);node[u].push_back(v);node[v].push_back(u);}for(int u=1;u<=n;u++) {if((int)node[u].size()>=sq) {for(auto v:node[u]) {big[v].push_back(u);}}}for(int i=1;i<=q;i++) {int u,w;read(u),read(w);val[u]+=w;t[val[u]].push_back({u,i});}for(int i=1;i<=n;i++) {second_last[i]=first_last[i]=big_mmin[i]=q;}for(int i=10000;i>=1;i--) {for(auto it:t[i]) {//遍歷每個新增加步數的位置int u=it.first,tim=it.second;for(auto v:big[u]) {//用小點更新大點的朋友圈big_mmin[v]=min(big_mmin[v],tim);}second_last[u]=first_last[u];first_last[u]=tim;}for(auto it:t[i]) {int u=it.first,tim=it.second;if((int)node[u].size()<sq) {//小點直接暴力找貢獻int mmin=second_last[u];for(auto v:node[u]) {mmin=min(mmin,first_last[v]);}ans[u]+=max(0,mmin-tim);} else {//大點直接用big_mmin計算貢獻ans[u]+=max(0,min(second_last[u],big_mmin[u])-tim);}}}for(int i=1;i<=n;i++) {printf("%d\n",ans[i]);}return 0; }

    總結

    以上是生活随笔為你收集整理的2021牛客多校2 - WeChat Walk(分块)的全部內容,希望文章能夠幫你解決所遇到的問題。

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