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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

牛客 - 红蓝图(克鲁斯卡尔重构树的dfs序上建主席树)

發(fā)布時間:2024/4/11 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 牛客 - 红蓝图(克鲁斯卡尔重构树的dfs序上建主席树) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一張 n 個點和 m 條邊組成的無向圖,每條邊都有邊權和顏色,顏色分為紅色和藍色,現在有 q 次相互獨立的操作,每次操作會詢問 ( x , t ) ,問刪除掉所有權值大于 t 的紅色邊和所有權值小于 t 的藍色邊后,x 所在的連通塊的大小是多少

注意,兩個點聯通,既需要存在著紅色的可達路徑,也需要存在著藍色的可達路徑

題目分析:如果去掉藍色邊的限制,只考慮 “刪除掉權值大于 t 的邊后,點 x 所在的連通塊的大小是多少” ,這就是個標準的克魯斯卡爾重構樹的dfs序問題,連線段樹都不用建了,直接輸出 R[ x ] - L[ x ] + 1 就是答案了(dfs序代表的子樹區(qū)間)

現在又有了藍色邊的限制,不難想到讓紅色邊和藍色邊單獨考慮,這樣每次詢問時,假設點 x 在紅色邊中對應子樹的 dfs 序為 [ l1 , r1 ],在藍色邊中對應子樹的 dfs 序為 [ l2 , r2 ],現在我們的問題轉換為了,這兩段區(qū)間對應到點 1 ~ n 中,交集的大小

因為樹上的 dfs 序與樹上的節(jié)點是一一對應的,換句話說克魯斯卡爾重構樹上的葉子節(jié)點的 dfs 序與點 1 ~ n 也是一一對應的,這樣就形成了一種對應關系:藍色樹上的 dfs 序 <=> 點 1 ~ n <=> 紅色樹上的 dfs 序,通過點 1 ~ n 做過渡,不難看出藍色樹上的 dfs 序與紅色樹上的 dfs 序中有 n 個點也存在著一一對應的關系,利用主席樹將其對應上就可以了

代碼:
?

//#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<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;struct Ex_Kruskal {struct Edge{int x,y,w;bool operator<(const Edge& t)const{return w<t.w;}}edge[N];int f[N],L[N],R[N],val[N],dp[N][25],id[N],tot,index,cnt,n;vector<int>node[N];void init(int n){cnt=tot=0;index=n;for(int i=0;i<=n<<1;i++){f[i]=i;node[i].clear();}}int find(int x){return f[x]==x?x:f[x]=find(f[x]);}void addedge(int x,int y,int w){edge[++cnt]={x,y,w};}void solve(){sort(edge+1,edge+1+cnt);for(int i=1;i<=cnt;i++){int xx=find(edge[i].x),yy=find(edge[i].y);if(xx!=yy){f[xx]=f[yy]=++index;node[index].push_back(xx);node[index].push_back(yy);val[index]=edge[i].w;}}n=index;for(int i=1;i<=n;i++)if(find(i)==i)dfs(i,0);}int get_pos(int x,int limit){for(int i=20;i>=0;i--)if(dp[x][i]&&val[dp[x][i]]<=limit)x=dp[x][i];return x;}void dfs(int u,int fa){L[u]=++tot;id[tot]=u;dp[u][0]=fa;for(int i=1;i<=20;i++)dp[u][i]=dp[dp[u][i-1]][i-1];for(auto v:node[u])dfs(v,u);R[u]=tot;} }t1,t2;struct Node {int l,r;int sum; }tree[N*20];int cnt,root[N];void update(int num,int &k,int l,int r) {tree[cnt++]=tree[k];k=cnt-1;tree[k].sum++;if(l==r)return;int mid=l+r>>1;if(num<=mid)update(num,tree[k].l,l,mid);elseupdate(num,tree[k].r,mid+1,r); }int query(int i,int j,int l,int r,int L,int R)//[l,r]:目標區(qū)間 [L,R]:當前區(qū)間 {if(L>r||R<l)return 0;if(L>=l&&R<=r)return tree[j].sum-tree[i].sum;int mid=L+R>>1;return query(tree[i].l,tree[j].l,l,r,L,mid)+query(tree[i].r,tree[j].r,l,r,mid+1,R); }void init() {root[0]=0;tree[0].l=tree[0].r=tree[0].sum=0;cnt=1; }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);init();int n,m,q;scanf("%d%d%d",&n,&m,&q);t1.init(n),t2.init(n);for(int i=1;i<=m;i++){int x,y,c;scanf("%d%d%d",&x,&y,&c);x++,y++;if(c==0)//redt1.addedge(x,y,i);else//bluet2.addedge(x,y,-i);}t1.solve(),t2.solve();for(int i=1;i<=t2.n;i++)//遍歷blue_tree的dfs序 {root[i]=root[i-1];if(t2.id[i]<=n)//i是t2的dfs序,t2.id[i]是在dfs序上對應的節(jié)點,t1.L[t2.id[i]]是對應在t1上的dfs序 update(t1.L[t2.id[i]],root[i],1,t1.n);}while(q--){int x,t;scanf("%d%d",&x,&t);x++;int pos1=t1.get_pos(x,t),pos2=t2.get_pos(x,-t);int l1=t1.L[pos1],r1=t1.R[pos1];//對應在t1上的dfs序范圍 int l2=t2.L[pos2],r2=t2.R[pos2];//對應在t2上的dfs序范圍printf("%d\n",query(root[l2-1],root[r2],l1,r1,1,t1.n));}return 0; }

?

總結

以上是生活随笔為你收集整理的牛客 - 红蓝图(克鲁斯卡尔重构树的dfs序上建主席树)的全部內容,希望文章能夠幫你解決所遇到的問題。

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