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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

洛谷P7518:宝石(倍增、可撤销并查集)

發布時間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷P7518:宝石(倍增、可撤销并查集) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

解析

算法一

定義 upx,kup_{x,k}upx,k? 為節點 xxx自己的顏色所在位置在返祖鏈上往后跳 2k2^k2k 個顏色到達的節點。
可以像倍增一樣的求解。
這樣對于一次詢問 (s,t)(s,t)(s,t) 我們就能求出 (s,lca)(s,lca)(s,lca) 這一段能取到哪里了。
對于向下的情況,再處理一個 upx,k′up'_{x,k}upx,k? 表示節點 xxx自己的顏色所在位置在返祖鏈上往2k2^k2k 個顏色到達的節點。
然后二分每一個詢問的答案,從答案開始往前跳,看能否與 (s,lca)(s,lca)(s,lca) 相接即可判定是否合法。
時間復雜度 O(nlog?n+mlog?Clog?n)O(n\log n+m\log C\log n)O(nlogn+mlogClogn)

算法二

考慮優化后一段 (lca,t)(lca,t)(lca,t) 的過程。
假設詢問 iii(s,lca)(s,lca)(s,lca) 過程中跳到了顏色 ccc,就在 lcalcalca 處增加一個 (i,c)(i,c)(i,c) 的元素,在 ttt 處打一個 (i)(i)(i) 標記。
考慮我們 dfsdfsdfs 過程中需要維護什么:

  • 插入二元組 (i,c)(i,c)(i,c)
  • 如果當前節點顏色為 ccc,收集器上的下一個顏色為 sufsufsuf,就使所有 (i,c)→(i,suf)(i,c)\to(i,suf)(i,c)(i,suf)
  • 查詢當前的 iii 元素的特征值。
  • 撤銷當前dfs的影響。
  • 這個東西可以用可撤銷并查集維護。
    總復雜度 O(nlog?n+mlog?n)O(n\log n+m\log n)O(nlogn+mlogn)

    代碼

    寫的是算法二。

    #include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define debug(...) fprintf(stderr,__VA_ARGS__) #define ok debug("OK\n") using namespace std;const int N=2e6+100; const int M=50050; const int mod=1e9+7; const double eps=1e-9;inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f; }int n,m,C,Mx;struct node{int to,nxt; }e[N<<1]; int fi[N],cnt; inline void addline(int x,int y){e[++cnt]=(node){y,fi[x]};fi[x]=cnt;return; } int p[N],col[N];int pre[N],up[N][20],pl[N][20],dep[N],suf[N]; void dfs(int x,int f){dep[x]=dep[f]+1;pl[x][0]=f;for(int k=1;pl[x][k-1];k++) pl[x][k]=pl[pl[x][k-1]][k-1];up[x][0]=pre[suf[col[x]]];for(int k=1;up[x][k-1];k++) up[x][k]=up[up[x][k-1]][k-1];int ori=pre[col[x]];pre[col[x]]=x;for(int i=fi[x];~i;i=e[i].nxt){int to=e[i].to;if(to==f) continue;dfs(to,x);}pre[col[x]]=ori;return; } inline int Lca(int x,int y){if(dep[x]<dep[y]) swap(x,y);for(int k=17;k>=0;k--){if(dep[pl[x][k]]<dep[y]) continue;x=pl[x][k];}if(x==y) return x;for(int k=17;k>=0;k--){if(pl[x][k]==pl[y][k]) continue;x=pl[x][k];y=pl[y][k];}return pl[x][0]; } struct query{int s,t,lca,id; }; vector<query>v[N]; inline int jump(int x,int top){//return color;for(int k=17;k>=0;k--){if(dep[up[x][k]]<dep[top]) continue;x=up[x][k];}return suf[col[x]]; } struct add{int id,c; }; vector<add>ad[N]; vector<int>q[N]; void solve1(int x,int f){int ori=pre[col[x]];pre[col[x]]=x;for(query o:v[x]){int s=o.s,t=o.t,lca=o.lca,id=o.id;s=pre[p[1]];if(dep[s]<dep[lca]) ad[lca].push_back((add){id,p[1]});else ad[lca].push_back((add){id,jump(s,lca)});q[t].push_back(id);}for(int i=fi[x];~i;i=e[i].nxt){int to=e[i].to;if(to==f) continue;solve1(to,x);}pre[col[x]]=ori;return; } int mx[N],fa[N],siz[N]; struct ope{int op;//1:fa 2:siz 3:mx 4:belint id,ori; }zhan[N<<3]; int top,nam[N],bel[N],tot; int find(int x){return fa[x]==x?x:find(fa[x]); } inline int New(int val){++tot;fa[tot]=tot;siz[tot]=1;mx[tot]=val;return tot; } void merge(int x,int y){x=find(x);y=find(y);if(siz[x]>siz[y]) swap(x,y);zhan[++top]=(ope){1,x,fa[x]};fa[x]=y;zhan[++top]=(ope){2,y,siz[y]};siz[y]+=siz[x];zhan[++top]=(ope){3,y,mx[y]};mx[y]=max(mx[y],mx[x]);return; } void del(int tim){while(top!=tim){if(zhan[top].op==1) fa[zhan[top].id]=zhan[top].ori;else if(zhan[top].op==2) siz[zhan[top].id]=zhan[top].ori;else if(zhan[top].op==3) mx[zhan[top].id]=zhan[top].ori;else if(zhan[top].op==4) bel[zhan[top].id]=zhan[top].ori;top--;}return; } int ans[N]; int rk[N]; void solve2(int x,int f){int ori=top;for(add o:ad[x]){int id=o.id,c=o.c,now=New(0);nam[id]=now;merge(now,bel[c]);//ans[id]=rk[c];}//assert(mx[find(bel[suf[col[x]]])]==rk[suf[col[x]]]);//assert(mx[find(bel[col[x]])]==rk[col[x]]);merge(bel[col[x]],bel[suf[col[x]]]);//if(mx[find(bel[col[x]])]!=rk[col[x]]+1){// debug("%d %d\n",mx[find(bel[col[x]])],rk[col[x]]);exit(0);//}//assert(mx[find(bel[col[x]])]==rk[col[x]]+1);zhan[++top]=(ope){4,col[x],bel[col[x]]};bel[col[x]]=New(rk[col[x]]);for(int id:q[x]){int o=nam[id];ans[id]=mx[find(o)];}for(int i=fi[x];~i;i=e[i].nxt){int to=e[i].to;if(to==f) continue;solve2(to,x);}del(ori); } int main() { #ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout); #endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();Mx=read();C=read();for(int i=1;i<=C;i++) p[i]=read();for(int i=1;i<=C;i++) suf[p[i]]=p[i+1],rk[p[i]]=i;rk[0]=C+1;for(int i=0;i<=Mx;i++) bel[i]=New(rk[i]);for(int i=1;i<=n;i++) col[i]=read();for(int i=1;i<n;i++){int x=read(),y=read();addline(x,y);addline(y,x);}dfs(1,0);m=read();for(int i=1;i<=m;i++){int s=read(),t=read(),lca=Lca(s,t);v[s].push_back((query){s,t,lca,i});}solve1(1,0);solve2(1,0);for(int i=1;i<=m;i++) printf("%d\n",ans[i]-1);return 0; } /* 1 3 3 1000000 2000000 0 0 */

    總結

    以上是生活随笔為你收集整理的洛谷P7518:宝石(倍增、可撤销并查集)的全部內容,希望文章能夠幫你解決所遇到的問題。

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