1. 程式人生 > >【做題】Codeforces Round #453 (Div. 1) D. Weighting a Tree——拆環

【做題】Codeforces Round #453 (Div. 1) D. Weighting a Tree——拆環

每一個 int 會有 while sig 實現 dex -s 怎麽辦

前言:結論題似乎是我的硬傷……

題意是給你一個無向圖,已知連接到每一個點的邊的權值和(為整數,且屬於區間[-n,n]),需要求出每條邊權值的一個合法解(都要是在區間[-2*n^2,2*n^2]內的整數)。

第一個想法當然是O(n^2*m)的高斯消元。在此基礎上,我想過通過選取某些節點,在邊權總和中減去與之相鄰的邊,來逐個解出邊的權值。這個本質上是優化解方程的辦法難以適應全部情況,且難以通過編程實現。於是只能舍棄這個想法。

後來通過漫無邊際的瞎想觀察標題,容易發現對於一棵樹求解這個問題是極為容易的。於是下一個思路就是把這個無向圖轉化為一棵樹。如下圖所示,偶環的情況是很容易就能解決的。(無腦刪邊)

技術分享圖片

那麽奇環怎麽辦呢?事實上,本人就卡在了這裏。如果按照偶環的方法來解釋奇環刪邊的合法性,我們發現最終有一個點的點權增加了2a。陷入僵局。這時,不妨讓我們再考慮一下對樹求解的過程。也就是一次dfs,對於除根結點之外的每一個結點都滿足其權值和,再根據根結點是否滿足其約束條件來判斷是否有解。註意到上面奇環的操作,實質就意味著如果我們以一個奇環上的點為根結點,那麽就可以在最後判斷的時候任意加上一個偶數了。容易證明,最後與根結點相鄰的邊權和與其應有的邊權和之差一定是一個偶數。也就是說,有奇環的圖是一定有解的。因此,我們如上的處理奇環的方式,並不會影響解的存在性。

於是,我們就得到了處理環的方式:都不鳥它,並從奇環上隨意拉一個點當根結點。

講到這裏,我們似乎還忽略了一個條件。

write a weight between ?-?2·n2 and n2 (inclusive) on each edge

當然,這個範圍是相當大的,一般而言解是一定在這個區間內的(也僅限一般而言)。基於cf是一個有hack機制的網站,毫無疑問會有數據把你的解卡出這個區間(對本人而言是test 34)。因此,random_shuffle是必不可缺的

時間復雜度O(n+m)。

  1 #include <bits/stdc++.h>
  2 #define int long long
  3 #define tag(i) (ed[((i)|1)>>1].id)
  4
using namespace std; 5 const int N = 100010; 6 struct edge { 7 int la,b; 8 edge(int la=0,int b=0):la(la),b(b) {}; 9 } con[N<<1]; 10 int tot=1,fir[N]; 11 void add(int from,int to) { 12 con[++tot] = edge(fir[from],to); 13 fir[from] = tot; 14 con[++tot] = edge(fir[to],from); 15 fir[to] = tot; 16 } 17 int c[N],ans[N],n,m,cnt,dep[N],rt,ano,fat[N],up[N],mar[N]; 18 typedef pair<int,int> pii; 19 struct data { 20 int a,b,id; 21 data(int a=0,int b=0,int id=0):a(a),b(b),id(id){} 22 } ed[N]; 23 pii ext[N]; 24 bool vis[N]; 25 void dfs_init(int pos,int fa) { 26 fat[pos] = fa; 27 vis[pos] = 1; 28 dep[pos] = dep[fa] + 1; 29 for (int i = fir[pos] ; i ; i = con[i].la) { 30 if (con[i].b == fa) continue; 31 if (vis[con[i].b]) { 32 if (pos > con[i].b) ext[++cnt] = pii(pos,i); 33 } else dfs_init(con[i].b,pos),up[con[i].b] = tag(i); 34 } 35 } 36 int dfs(int pos,int fa) { 37 vis[pos] = 1; 38 int now = c[pos]; 39 for (int i = fir[pos] ; i ; i = con[i].la) { 40 if (vis[con[i].b]) continue; 41 now -= (ans[tag(i)] = dfs(con[i].b,pos)); 42 } 43 return now; 44 } 45 bool ocy(pii x) { 46 int a = x.first, b = con[x.second].b; 47 return (dep[a] + dep[b] + 1)&1; 48 } 49 void print() { 50 puts("YES"); 51 for (int i = 1 ; i <= m ; ++ i) { 52 cout << ans[i] << endl; 53 } 54 } 55 void modify(int x,int y) { 56 int k1 = 1, k2 = -1; 57 while (dep[x] > dep[y]) { 58 mar[up[x]] += k1; 59 k1 = -k1; 60 x = fat[x]; 61 } 62 while (dep[y] > dep[x]) { 63 mar[up[y]] += k2; 64 k2 = -k2; 65 y = fat[y]; 66 } 67 while (x != y) { 68 mar[up[x]] += k1; 69 k1 = -k1; 70 x = fat[x]; 71 mar[up[y]] += k2; 72 k2 = -k2; 73 y = fat[y]; 74 } 75 } 76 signed main() { 77 int a,b; 78 cin >> n >> m; 79 for (int i = 1 ; i <= n ; ++ i) cin>>c[i]; 80 for (int i = 1 ; i <= m ; ++ i) { 81 cin >> a >> b; 82 ed[i] = data(a,b,i); 83 } 84 random_shuffle(ed+1,ed+m+1); 85 for (int i = 1 ; i <= m ; ++ i) add(ed[i].a,ed[i].b); 86 dfs_init(1,0); 87 for (int i = 1 ; i <= cnt ; ++ i) { 88 if (ocy(ext[i])) { 89 rt = ext[i].first, ano = con[ext[i].second].b; 90 modify(rt,ano); 91 mar[tag(ext[i].second)] ++; 92 break; 93 } 94 } 95 memset (vis,0,sizeof vis); 96 if (rt) { 97 int uns = dfs(rt,0)>>1; 98 for (int i = 1 ; i <= m ; ++ i) ans[i] += mar[i] * uns; 99 print(); 100 } else { 101 if (dfs(1,0) != 0) puts("NO"); 102 else print(); 103 } 104 return 0; 105 }

小結:關於我卡在奇環無從下手,應該是缺乏與實際算法的運行相結合。

【做題】Codeforces Round #453 (Div. 1) D. Weighting a Tree——拆環