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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

蓝桥备赛第四周 同余+并查集

發布時間:2024/10/8 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 蓝桥备赛第四周 同余+并查集 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 0x33 同余
    • 同余類+剩余系+費馬小定理+歐拉定理及推論
    • 最幸運的數字
      • 題解
      • 這次的代碼很多東西:歐拉函數快速求解,gcd,快速乘,各種定理,建議當模板背
        • 10LL 轉換成長整型
        • 快速乘+快速冪(取模)模板
        • 技巧:試除法可以一半一半求,減少遍歷次數,兩半都用稠密的一半遍歷(因子是成對的)
    • 擴展歐幾里得算法
      • ax+by=gcd(a,b)存在至少一組整數解xy
    • 乘法逆元
    • sumdiv
      • 新的逆元做法,下次再做吧
    • 線性同余方程
    • 同余方程
      • 就是exgcd的模板題
    • 中國剩余定理
    • 表達整數的奇怪方式
      • 思路
      • 看題解更好些
        • 沒法一口氣求解,只能一個一個往上增加
  • 0x41并查集
        • 這個東西很適合搞圖的連通性==“擅長維護傳遞性”
    • 模板
    • 程序自動分析
      • 標準的并查集題
        • 不想離散化,所以map版并查集,但會有一組TLE
        • 在map基礎上,把相等的和不等的分開存儲,空間*2,時間/2,牛客能過了,acwing多過了幾條數據,但還是7組
        • 我透了,改個unordered_map就能過,或者開O2(O2不能過)
      • 2021.3.7復習解法(能過前九個):有個很不錯的結構體寫法
    • supermarket
    • 擴展域與邊帶權的并查集
    • 銀河英雄傳說
      • 雖然dx的變化有一半是寫在get里面的,但如果不merge,fa[x]指向的是當前根節點,根節點dx為0,dx+=d【fa【x】】不會發生改變-----------每一次merge,對每個節點只+1次,且不會影響其他同集合的節點
      • 帶圖的題解
        • 另外有的標準size是關鍵字,不能用,不過編譯
      • 銀河英雄傳說---邊權集2021.3.8復習---有注釋!
      • 2021.4.17研究出來的模板
    • 奇偶游戲
      • 邊權集解法
        • 先將正常數組改成前綴和,變成兩個點的奇偶性,這樣“權”就可以變成d[x](x與根之間),奇偶性的話,就用抑或來計算,如果已經有了,那么通過dx來計算x與y之間奇偶性,如果沒有聯通,那么要通過已知x與y之間奇偶性,倒推兩個根節點之間的奇偶性,合并,另外數很稀疏,考慮離散化
        • acwing秦淮河大佬的復現書上代碼,思路很棒
      • 擴展域解法(這個很簡單,維護兩個域,互相也是聯通的,不用算權值了)
      • 擴展域解法1.不要忘了初始化2.不要忘了-1 3.擴展域一定要放一個數組里 ------------2021.3.8復習
    • 食物鏈
      • 拓展域
        • 三個域
        • 2021.3.8復習:這里的捕食域,同類域,天敵域,通過三個域表達出了方向關系(X被Y捕食,Y是X的天敵):通過X的Xself 與 Y的 Yeat 聯通
      • 邊帶權
        • 把吃,被吃,同類設為 1,2,0,每次維護就好

0x33 同余

同余類+剩余系+費馬小定理+歐拉定理及推論



最幸運的數字

現在給定一個正整數L,請問至少多少個8連在一起組成的正整數 (即最小幸運數字)是L的倍數。 輸入格式 輸入包含多組測試用例。 每組測試用例占一行,包含一個整數L。 當輸入用例L=0時,表示輸入終止,該用例無需處理。 輸出格式 每組測試用例輸出結果占一行。 結果為“Case 1:+一個整數N,N代表滿足條件的最小幸運數字的位數。 如果滿足條件的幸運數字不存在,則N=0。 數據范圍 1≤L≤2?109 輸入樣例: 8 11 16 0 輸出樣例: Case 1: 1 Case 2: 2

題解

這次的代碼很多東西:歐拉函數快速求解,gcd,快速乘,各種定理,建議當模板背

10LL 轉換成長整型

快速乘+快速冪(取模)模板

技巧:試除法可以一半一半求,減少遍歷次數,兩半都用稠密的一半遍歷(因子是成對的)

#include"stdio.h" #include"string.h" #include"math.h" #include"algorithm" using namespace std; typedef long long ll;ll L;ll gcd(ll a,ll b) {if(a < b){ll t = a; a = b; b = t;}if(b == 0)return a;return gcd(b,a%b); } ll multi(ll a,ll b,ll mod) {ll ans = 0;while(b){if(b & 1)ans = (ans + a) % mod;a = (a << 1) % mod;b = b >> 1;}return ans; } ll Ola(ll n) {ll sum = n;for(int i = 2; i * i<= n; i ++){if(n % i)continue;sum = sum / i * (i - 1);while(n % i == 0)n = n / i;}if(n != 1)sum = sum / n * (n - 1);return sum; } int Quick(ll a,ll b,ll mod) ///a:10LL b:歐拉函數的因子,也就是次數 mod:9L/d ///這個就是快速冪,套了快乘的快速冪(因為mod可能很大) {ll ans = 1; a %= mod;///a與n互質///a %= mod;不加也能過while(b){if(b & 1)ans = multi(ans,a,mod);b >>= 1;a = multi(a,a,mod);}if(ans == 1)return 1;return 0; } ll solve() {ll g = L / gcd(L,8LL) * 9;///LL轉換,g是9L除以dif(gcd(10LL,g) != 1) return 0;///a,n互質才有解ll sum = 1;ll num = Ola(g); ///把g的歐拉函數求出來///下面這個for是試除法求因子for(int i = 1; i * (ll)i <= num; i ++){if(num % i) continue;///是因子就看看能不能余g///這個quick有個10LL的參數應該也是模板if(Quick(10LL,(ll)i,g) == 1)return i;}///依舊是試除法求因子,不過求的是大于根號的這一半(因為小于根號這一半較小嘛,更好求)ll m = sqrt(num);for(int i = m; i >= 1; i --){if(num % i == 0 && Quick(10LL,num / i,g) == 1)return num / i;}return 0; }int main() {int cnt = 1;while(~scanf("%lld",&L)){if(L == 0) break;printf("Case %d: %lld\n",cnt ++,solve());} }

擴展歐幾里得算法

ax+by=gcd(a,b)存在至少一組整數解xy


乘法逆元


sumdiv

新的逆元做法,下次再做吧


線性同余方程


同余方程

求關于x的同余方程 ax ≡ 1(mod b) 的最小正整數解。輸入格式 輸入只有一行,包含兩個正整數a,b,用一個空格隔開。輸出格式 輸出只有一行,包含一個正整數x,表示最小正整數解。輸入數據保證一定有解。數據范圍 2≤a,b≤2?109 輸入樣例: 3 10 輸出樣例: 7

就是exgcd的模板題


#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll;ll a,b,x,y; ll exgcd(ll a,ll b,ll &x,ll &y) {if(b==0){x=1,y=0;return a;}int d=exgcd(b,a%b,x,y);int z=x;x=y;y=z-y*(a/b);return d; } int main() {cin>>a>>b;exgcd(a,b,x,y);cout<<(x%b+b)%b<<endl;return 0; }

中國剩余定理


表達整數的奇怪方式

給定 2n 個整數a1,a2,,an和m1,m2,,mn,求一個最小的非負整數 x,滿足?i∈[1,n],x≡mi(mod ai)。輸入格式 第1 行包含整數 n。第 2..n+1行:每 i+1 行包含兩個整數ai和mi,數之間用空格隔開。輸出格式 輸出最小非負整數 x,如果 x 不存在,則輸出 ?1。 如果存在 x,則數據保證 x 一定在64位整數范圍內。數據范圍 1≤ai≤231?1, 0≤mi<ai 1≤n≤25 輸入樣例: 2 8 7 11 9 輸出樣例: 31

思路

看題解更好些

沒法一口氣求解,只能一個一個往上增加


#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long LL; int n; LL exgcd(LL a, LL b, LL &x, LL &y){///exgcdif(b == 0){x = 1, y = 0;return a;}LL d = exgcd(b, a % b, y, x);y -= a / b * x;return d; } LL inline mod(LL a, LL b){///防止負數的取模(最小化到0~b-1)return ((a % b) + b) % b; } int main() {cin>>n;LL a1,m1;cin>>a1>>m1;for(int i=1;i<n;i++)///每輸入一組都要合并{LL a2,m2,k1,k2;cin>>a2>>m2;LL d=exgcd(a1,-a2,k1,k2);///if((m2-m1)%d){///不是因數(不能整除),無解cout<<-1<<endl;return 0;}k1=mod(k1*(m2-m1)/d,abs(a2/d));m1=k1*a1+m1;///產生新的a1和m1a1=abs(a1/d*a2);}cout<<m1<<endl;return 0; }

0x41并查集

這個東西很適合搞圖的連通性==“擅長維護傳遞性”



模板

int fa[maxn]; void init() {for(int i=0;i<maxn;i++){fa[maxn]=i;} } int get(int x) {if(x==fa[x])return x;return fa[x]=get(fa[x]); } int mergefa(int x,int y) {fa[get(x)]=get(y); }

程序自動分析

標準的并查集題


不想離散化,所以map版并查集,但會有一組TLE

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 1000005 map<int,int> fa; int n; int xi[maxn]; int yi[maxn]; int ei[maxn]; int get(int x) {if(fa[x]==0||x==fa[x])///這個if應該是短路運算符///不過不加fa[x]==0||也行,已經把賦初值拆分了///map沒賦過值的為0{fa[x]=x;///給沒賦過值的準備的return x;}return fa[x]=get(fa[x]); } void mergefa(int x,int y) {fa[get(x)]=get(y); } int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t;cin>>t;while(t--){fa.clear();///初始化要做好int n;cin>>n;for(int i=0;i<n;i++){cin>>xi[i]>>yi[i]>>ei[i];}///先算一遍等于號的for(int i=0;i<n;i++){int x=xi[i];int y=yi[i];if(ei[i]==1){if(fa[x]==0){fa[x]=x;///賦初值拆分進來}if(fa[y]==0){fa[y]=y;///賦初值拆分進來}//mergefa(x,y);}}///不等于的int flag=1;for(int i=0;i<n;i++){int x=xi[i];int y=yi[i];if(ei[i]==0){if(fa[x]==0){fa[x]=x;///賦初值拆分進來}if(fa[y]==0){fa[y]=y;///賦初值拆分進來}if(get(x)==get(y)){flag=0;break;}else{continue;}}}if(flag){cout<<"YES"<<endl;}else{cout<<"NO"<<endl;}}return 0; }

在map基礎上,把相等的和不等的分開存儲,空間*2,時間/2,牛客能過了,acwing多過了幾條數據,但還是7組

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 1000005 map<int,int> fa; int n; int xi[maxn]; int yi[maxn];int xp[maxn]; int yp[maxn]; int get(int x) {if(x==fa[x])///這個if應該是短路運算符///不過不加fa[x]==0||也行,已經把賦初值拆分了///map沒賦過值的為0{fa[x]=x;///給沒賦過值的準備的return x;}return fa[x]=get(fa[x]); } void mergefa(int x,int y) {fa[get(x)]=get(y); } int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t;cin>>t;while(t--){fa.clear();///初始化要做好int n;cin>>n;int e;int bufx,bufy,bufe;int cnt1,cnt0;cnt1=cnt0=0;for(int i=0;i<n;i++){cin>>bufx>>bufy>>bufe;if(bufe==1){xi[cnt1]=bufx;yi[cnt1++]=bufy;}if(bufe==0){xp[cnt0]=bufx;yp[cnt0++]=bufy;}}for(int i=0;i<cnt1;i++){int x=xi[i];int y=yi[i];if(fa[x]==0){fa[x]=x;///賦初值拆分進來}if(fa[y]==0){fa[y]=y;///賦初值拆分進來}//mergefa(x,y);}///不等于的int flag=1;for(int i=0;i<cnt0;i++){int x=xp[i];int y=yp[i];if(fa[x]==0){fa[x]=x;///賦初值拆分進來}if(fa[y]==0){fa[y]=y;///賦初值拆分進來}if(get(x)==get(y)){flag=0;break;}else{continue;}}if(flag){cout<<"YES"<<endl;}else{cout<<"NO"<<endl;}}return 0; }

我透了,改個unordered_map就能過,或者開O2(O2不能過)

2021.3.7復習解法(能過前九個):有個很不錯的結構體寫法

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 1000005 int fa[maxn]; struct uneq{int a;int b; }uneqs[maxn]; void initfa() {for(int i=0;i<maxn;i++){fa[i]=i;}} int getfa(int x) {if(fa[x]==x)return fa[x];return fa[x]= getfa(fa[x]); } int mergefa(int a,int b) {fa[getfa(a)]=getfa(b); } int main() {int t;cin>>t;while(t--){initfa();int n;cin>>n;int cntuneq=0;int bufa,bufb,bufc;while(n--){cin>>bufa>>bufb>>bufc;if(bufc==1){mergefa(bufa,bufb);}if(bufc==0){uneqs[cntuneq++]={bufa,bufb};///新的結構體寫法很有趣}} // for(int i=0;i<cntuneq;i++) // { // cout<< uneqs[i].a<<uneqs[i].b; // }int flag=1;for(int i=0;i<cntuneq;i++){if(getfa(uneqs[i].a)==getfa(uneqs[i].b)){flag=0;break;}}if(flag){cout<<"YES"<<endl;}else{cout<<"NO"<<endl;}}return 0; }

supermarket

0x17


擴展域與邊帶權的并查集



銀河英雄傳說


雖然dx的變化有一半是寫在get里面的,但如果不merge,fa[x]指向的是當前根節點,根節點dx為0,dx+=d【fa【x】】不會發生改變-----------每一次merge,對每個節點只+1次,且不會影響其他同集合的節點

帶圖的題解

另外有的標準size是關鍵字,不能用,不過編譯

#include <bits/stdc++.h> using namespace std; const int N=31000+10; int fa[N],n,t,i,j,d[N],size[N];//size就是記錄個數 int get(int x) {if (x==fa[x])return x;int root=get(fa[x]);d[x]+=d[fa[x]];//往下推進return fa[x]=root; } void merge(int x,int y) {x=get(x),y=get(y);fa[x]=y,d[x]=size[y];size[y]+=size[x];//順帶記錄 } int main() {scanf("%d\n",&t);for(i=1;i<=30000;i++)fa[i]=i,size[i]=1;while(t--){char ch=getchar();scanf("%d %d\n",&i,&j);if (ch=='M'){merge(i,j);}else{if (get(i)==get(j))cout<<abs(d[i]-d[j])-1;elsecout<<"-1";cout<<endl;}}return 0; }

銀河英雄傳說—邊權集2021.3.8復習—有注釋!

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 100005 int fa[maxn]; int d[maxn];///記錄戰艦x與fa[x]之間邊的權值///初值為0 int sizefa[maxn];/// 記錄樹的大小,初值1 void initfa() {for(int i=0;i<maxn;i++){fa[i]=i;}} int getfa(int x) {if(fa[x]==x)return x;return fa[x]=getfa(fa[x]); } int newgetfa(int x) {if(fa[x]==x)return x;int root=getfa(fa[x]);///先存出來,集合代表d[x]+=d[fa[x]]///樹根變成了新的樹根,----對邊權求和///到維護前樹根的距離+維護前樹根到新樹根的距離return fa[x]=root;} void mergefa(int a,int b) {fa[getfa(a)]=getfa(b); } void mergefa(int a,int b)///之前提到了需要+維護前樹根到新樹根的距離 { ///那么這個距離需要兩個步驟d[getfa(a)]=fasize(getfa(b));///1.接到尾部,舊樹根的邊權d[x](到新樹根距離)就是目標樹的size(邊數)fasize[get(fa(b))]+=fasize[getfa(b)];///2.成為新樹,size變大fa[getfa(a)]=getfa(b);} int main() {return 0; }

2021.4.17研究出來的模板

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 1005 int fa[maxn]; int d[maxn]; void initfa() {for(int i=1;i<=n;i++){fa[i]=i;} } int getfa(int x) {if(fa[x]==x)return x;///這兩行就是維護權值數組int root=fa[x];d[x]+=d[fa[x]];return fa[x]=root; } void mergefa(int x,int y) {///這行是方便使用rx=getfa(x);ry=getfa(y);///這兩行是維護權值數組d[rx]=d[ry]+1;//d[rx]=size(y);sizem[y]+=sizem[x];///這行是原來的fa[x]=ry;}} int main() {return 0; }

奇偶游戲

邊權集解法

先將正常數組改成前綴和,變成兩個點的奇偶性,這樣“權”就可以變成d[x](x與根之間),奇偶性的話,就用抑或來計算,如果已經有了,那么通過dx來計算x與y之間奇偶性,如果沒有聯通,那么要通過已知x與y之間奇偶性,倒推兩個根節點之間的奇偶性,合并,另外數很稀疏,考慮離散化


acwing秦淮河大佬的復現書上代碼,思路很棒

#include<bits/stdc++.h> using namespace std; const int N=10010<<1; struct node {int l,r,ans; } q[N]; int a[N],fa[N],d[N],n,m,t_n; int get(int x) {if (x==fa[x])return x;int root=get(fa[x]);d[x]^=d[fa[x]];//異或return fa[x]=root; } inline int read_init()//離散化 {cin>>n>>m;for(int i=1;i<=m;i++){char str[5];scanf("%d%d%s",&q[i].l,&q[i].r,str);q[i].ans=(str[0]=='e'?0:1);a[++t_n]=q[i].l-1;a[++t_n]=q[i].r;}sort(a+1,a+1+t_n);n=unique(a+1,a+1+t_n)-a-1;//去重 } inline int work() {read_init();for(int i=1;i<=n;i++)fa[i]=i;for(int i=1;i<=m;i++){int x=lower_bound(a+1,a+1+n,q[i].l-1)-a;//離散化后要找數int y=lower_bound(a+1,a+1+n,q[i].r)-a;int p=get(x),q2=get(y);if (p==q2){if ((d[x]^d[y])!=q[i].ans)//變量要相等,但是卻不相等了.{cout<<i-1<<endl;return 0;}}else{fa[p]=q2;//合并merge.兩方代碼就懶得寫函數了,見諒d[p]^=d[x]^d[y]^q[i].ans;//統統異或}}cout<<m;//數據過于優秀,一個問題都沒有 } int main() {work();return 0; }

擴展域解法(這個很簡單,維護兩個域,互相也是聯通的,不用算權值了)


//Wan Hong 3.0 //notebook #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <queue>typedef long long ll; typedef std::pair<ll,ll> pll; ll read() {ll x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;else c=getchar();}while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x; } ll min(ll a,ll b) {return a<b?a:b; } ll max(ll a,ll b) {return a>b?a:b; } bool umin(ll &a,ll b) {if(b<a)return a=b,1;return 0; } bool umax(ll &a,ll b) {if(b>a)return a=b,1;return 0; } ll abs(ll x) {return x>0?x:-x; } /**********/ #define MAXN 100011 struct ufs {ll fa[MAXN];void build(ll n){for(ll i=0;i<=n;++i)fa[i]=i;}ll find(ll x){if(fa[x]==x)return x;return fa[x]=find(fa[x]);}void uni(ll u,ll v){u=find(u),v=find(v);fa[u]=v;}bool same(ll u,ll v){return find(u)==find(v);} }s; struct query {ll l,r,k;query(){}query(ll _l,ll _r,ll _k){l=_l,r=_r,k=_k;} }q[MAXN]; ll a[MAXN]; ll cnt=0; void disc() {std::sort(a+1,a+cnt+1);cnt=std::unique(a+1,a+cnt+1)-(a+1); } ll place(ll x) {return std::lower_bound(a+1,a+cnt+1,x)-a; } int main() {ll n=read(),m=read();for(ll i=1;i<=m;++i){ll l=read()-1,r=read();char c=getchar();while(c!='e'&&c!='o')c=getchar();q[i]=query(l,r,c=='o');a[++cnt]=l,a[++cnt]=r;}disc();s.build(cnt<<1);//[1,cnt]:x_even;[cnt+1,2cnt]:x_oddfor(ll i=1;i<=m;++i){ll l=place(q[i].l),r=place(q[i].r),k=q[i].k;ll l_even=l,l_odd=l+cnt,r_even=r,r_odd=r+cnt;if(!k){if(s.same(l_odd,r_even)||s.same(l_even,r_odd)){printf("%lld\n",i-1);return 0;}else s.uni(l_odd,r_odd),s.uni(l_even,r_even);}else{if(s.same(l_even,r_even)||s.same(l_odd,r_odd)){printf("%lld\n",i-1);return 0;}else s.uni(l_even,r_odd),s.uni(l_odd,r_even);}}printf("%lld",m);return 0; }作者:whsstory 鏈接:https://www.acwing.com/solution/content/4338/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

擴展域解法1.不要忘了初始化2.不要忘了-1 3.擴展域一定要放一個數組里 ------------2021.3.8復習

#include <iostream> #include<bits/stdc++.h> using namespace std; typedef long long ll; #define maxn 100005 int fa[maxn];///擴展域應該放在同一個數組里使用,x,x+n,x+n+n,x+n+n+n,......這樣才能測試是否聯通 int d[maxn]; int sizefa[maxn]; void initfa() {for(int i=0;i<maxn;i++){fa[i]=i;}} int getfa(int x) {if(fa[x]==x)return x;return fa[x]=getfa(fa[x]); } void mergefa(int a,int b) {fa[getfa(a)]=getfa(b); } int main() {initfa();int n;cin>>n;int t;cin>>t;int t2=t;int a,b,op;while(t--){cin>>a>>b>>op;if(op==0)///even{if(getfa(a-1)==getfa(b+n))///is odd--矛盾{cout<<t2-t<<'*';return 0;}mergefa(a-1,b);mergefa(a-1+n,b+n);}else{if(getfa(a-1)==getfa(b)){cout<<t2-t<<"#";return 0;}mergefa(a-1,b+n);mergefa(a-1+n,b);}}return 0; }

食物鏈

拓展域

三個域

//這里我們將三個域,分別轉化為了n,n+n,n+n+n.因為讀入方面特別煩. #include <bits/stdc++.h> using namespace std; int fa[200000]; int n,m,k,x,y,ans; int get(int x) {if(x==fa[x])return x;return fa[x]=get(fa[x]); } void merge(int x,int y) {fa[get(x)]=get(y); } int main() {cin>>n>>m;for(int i=1;i<=3*n;i++)fa[i]=i;for(int i=1;i<=m;i++){scanf("%d%d%d",&k,&x,&y);if(x>n || y>n)ans++;///假話總數+1else if(k==1)///同類{if(get(x)==get(y+n) || get(x)==get(y+n+n))//如果x,y是同類,但是x是y的捕食中的動物,或者x是y天敵中的動物,那么錯誤.ans++;///假話總數+1else{merge(x,y);merge(x+n,y+n);merge(x+n+n,y+n+n);}}else///X捕食Y{if(x==y || get(x)==get(y) || get(x)==get(y+n))//x就是y,或者他們是同類,再或者是y的同類中有xans++;//都是假話else{merge(x,y+n+n);//y的天敵域加入xmerge(x+n,y);//x的捕食域加入ymerge(x+n+n,y+n);//x的天敵域是y的捕食域.}}}cout<<ans<<endl; } //x是同類域. //x+n是捕食域 //x+n+n是天敵域

2021.3.8復習:這里的捕食域,同類域,天敵域,通過三個域表達出了方向關系(X被Y捕食,Y是X的天敵):通過X的Xself 與 Y的 Yeat 聯通

邊帶權

把吃,被吃,同類設為 1,2,0,每次維護就好

#include<bits/stdc++.h> using namespace std; const int maxn = 5e4 + 233; int fa[maxn], d[maxn]; int ff(int x) {if(fa[x] == x) return x;int r = ff(fa[x]);d[x] += d[fa[x]];return fa[x] = r; } int main() {int n,k; cin >> n >> k;for(int i = 0; i <= n; i++) fa[i] = i;int ans = 0;for(int i = 1; i <= k; i++){int t, a, b;scanf("%d%d%d", &t, &a, &b);if(a > n || b > n) {ans ++; continue;}else if(t == 2 && a == b) {ans++; continue;}else{int rel;if(t == 2) rel = 1;else rel = 0;int x = ff(a), y = ff(b);if(x == y) {if((((d[a] - d[b]) % 3) + 3) % 3 != rel)ans++;}else{fa[x] = y;d[x] = d[b] - (d[a] - rel);}}}cout<< ans; }作者:這個顯卡不太冷 鏈接:https://www.acwing.com/solution/content/1357/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

總結

以上是生活随笔為你收集整理的蓝桥备赛第四周 同余+并查集的全部內容,希望文章能夠幫你解決所遇到的問題。

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