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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【IOI2018】狼人【Kruscal重构树】【主席树】

發布時間:2023/12/3 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【IOI2018】狼人【Kruscal重构树】【主席树】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:nnn個點mmm條邊的無向圖,qqq次詢問,每次給定s,t,L,Rs,t,L,Rs,t,L,R,判斷是否存在一條sssttt的路徑,使得路徑上可以找到一點kkk,滿足此路徑s~ks\sim ksk的部分標號都≥L\geq LLk~tk\sim tkt標號都≤R\leq RR(均包括端點)

n,q≤2×105,m≤4×105n,q\leq2\times10^5,m\leq4\times10^5n,q2×105,m4×105

顯然找到sss只走≥L\geq LL的點能到達的點集SSS,ttt只走≤R\leq RR能到達TTT,判斷SSSTTT是否有交即可

分別從大到小和從小到大建出Kruscal重構樹,發現SSSTTT是樹上的一個子樹

什么?只有點權怎么建Kruscal重構樹?

因為你走一條邊實際上受到了兩個端點的限制,所以直接取兩個點的min?/max?\min/\maxmin/max當邊權就可以了

然后對SSSTTT跑dfs序,設兩個dfs序數組分別為dfsa,dfsbdfsa,dfsbdfsa,dfsb

那么對于uuu點可以映射成平面上的(dfsau,dfsbu)(dfsa_u,dfsb_u)(dfsau?,dfsbu?)

二維數點即可

因為橫縱坐標分別互不相同,所以寫主席樹會很清真

注意建Kruscal重構樹的虛點不要加到主席樹里面,否則會出奇怪的問題

復雜度O(nlog?n)O(n\log n)O(nlogn)

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #define MAXN 600005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } struct edge{int u,v;}e[MAXN]; int n,m,q; inline bool cmp1(const edge& a,const edge& b){return max(a.u,a.v)<max(b.u,b.v);} inline bool cmp2(const edge& a,const edge& b){return min(a.u,a.v)>min(b.u,b.v);} inline int Min(const int& x,const int& y){return x<y? x:y;} inline int Max(const int& x,const int& y){return x>y? x:y;} struct KruscalRestructTree {int f[MAXN],fa[MAXN][20],ch[MAXN][2],val[MAXN],cnt;int dfn[MAXN],ed[MAXN],pos[MAXN],tim;int find(int x){return f[x]==x? x:f[x]=find(f[x]);}inline void init(){cnt=n;for (int i=1;i<=n;i++) val[i]=i;for (int i=1;i<=n+m;i++) f[i]=i;}inline void insert(int u,int v,int m(const int&,const int&)){u=find(u),v=find(v);if (u==v) return;f[u]=f[v]=fa[u][0]=fa[v][0]=++cnt;ch[cnt][0]=u,ch[cnt][1]=v;val[cnt]=m(val[u],val[v]);}void dfs(int u){if (!u) return;pos[dfn[u]=++tim]=u;for (int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];dfs(ch[u][0]),dfs(ch[u][1]);ed[u]=tim;}inline void query(int u,int& l,int& r,int ql,int qr){if (val[u]<ql||qr<val[u]) return (void)(l=0);for (int i=19;i>=0;i--)if (fa[u][i]&&ql<=val[fa[u][i]]&&val[fa[u][i]]<=qr)u=fa[u][i];l=dfn[u],r=ed[u];} }S,T; int ch[MAXN<<5][2],sum[MAXN<<5],cnt; int rt[MAXN]; void insert(int& x,int y,int l,int r,int k) {x=++cnt;ch[x][0]=ch[y][0],ch[x][1]=ch[y][1],sum[x]=sum[y]+1;if (l==r) return;int mid=(l+r)>>1;if (k<=mid) insert(ch[x][0],ch[y][0],l,mid,k);else insert(ch[x][1],ch[y][1],mid+1,r,k); } int query(int x,int l,int r,int ql,int qr) {if (ql<=l&&r<=qr) return sum[x];if (qr<l||r<ql) return 0;int mid=(l+r)>>1;return query(ch[x][0],l,mid,ql,qr)+query(ch[x][1],mid+1,r,ql,qr); } int main() {n=read(),m=read(),q=read();S.init(),T.init();for (int i=1;i<=m;i++) e[i].u=read()+1,e[i].v=read()+1;sort(e+1,e+m+1,cmp2);for (int i=1;i<=m;i++) S.insert(e[i].u,e[i].v,Min);sort(e+1,e+m+1,cmp1);for (int i=1;i<=m;i++) T.insert(e[i].u,e[i].v,Max);int tot=S.cnt;S.dfs(tot),T.dfs(tot);for (int i=1;i<=tot;i++) if (S.pos[i]<=n) insert(rt[i],rt[i-1],1,tot,T.dfn[S.pos[i]]);else rt[i]=rt[i-1];while (q--){int s,t,l,r;s=read()+1,t=read()+1,l=read()+1,r=read()+1;int lx,rx,ly,ry;S.query(s,lx,rx,l,tot),T.query(t,ly,ry,1,r);if (!lx||!ly){puts("0");continue;}int ans=query(rt[rx],1,tot,ly,ry)-query(rt[lx-1],1,tot,ly,ry);printf("%d\n",!!ans);}return 0; }

總結

以上是生活随笔為你收集整理的【IOI2018】狼人【Kruscal重构树】【主席树】的全部內容,希望文章能夠幫你解決所遇到的問題。

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