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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Codeforces 1188A 构造

發布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Codeforces 1188A 构造 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:給你一顆樹,樹的邊權都是偶數,并且邊權各不相同。你可以選擇樹的兩個葉子結點,并且把兩個葉子結點之間的路徑加上一個值(可以為負數),問是否可以通過這種操作構造出這顆樹?如果可以,輸出構造方案。初始樹的邊權都是0。

思路:A1很簡單,只要判斷是否有度數為2的點就可以了。對于A2, 由于邊權各不相同,所以A1的結論同樣適用。現在我們來構造一組答案。官方題解的構造方式是這樣的:我們假設要讓一個節點u到葉子結點v的路徑都加上一個值x,并且知道葉子結點l1, l2都可以到達u,我們執行以下操作:v到l1的路徑加上x / 2, v到l2的路徑加上x / 2, l1 到 l2的路徑加上-x / 2,這樣除了u到v的路徑,其它路徑的值沒有變(太菜了,想不到。。。)。那么,我們從樹根開始,從上到下逐個構造邊權即可。

由于n只有1000,所以實現方式有兩種。

第一種很暴力,賦值操作直接暴力加,復雜度O(n ^ 2)。

代碼:

#include <bits/stdc++.h> #define pii pair<int, int> #define LL long long using namespace std; const int maxn = 1010; vector<pii> G[maxn]; vector<int> son[maxn]; LL add[maxn]; struct node {int x, y;LL z; }; vector<node> ans; int root = 1; int f[maxn]; void adde(int x, int y, int z) {G[x].push_back(make_pair(y, z));G[y].push_back(make_pair(x, z)); }int dfs(int x, int fa) {f[x] = fa;for (auto y : G[x]) {if(y.first== fa) continue;int tmp = dfs(y.first, x);son[x].push_back(tmp);}if(G[x].size() == 1) {return x;}return son[x][0]; }void update(int x, int p, int val) {while(x != p) {add[x] += val;x = f[x];} } void dfs1(int x, int fa) {int cnt = 0;if(x == root) {int y = G[x][0].first;if(G[y].size() == 1) {ans.push_back((node){x, y, G[x][0].second});return;}LL tmp = G[x][0].second;ans.push_back((node){son[y][0], root, tmp / 2});ans.push_back((node){son[y][1], root, tmp / 2});ans.push_back(node{son[y][0], son[y][1], -tmp / 2});dfs1(y, x);} else {for (auto y : G[x]) {if(y.first == fa) continue;LL tmp = y.second - add[y.first];int tmp1;if(cnt == 0) tmp1 = 1;else tmp1 = 0;ans.push_back((node){son[x][cnt], root, tmp / 2});ans.push_back((node){son[x][cnt], son[x][tmp1], tmp / 2});ans.push_back(node{root, son[x][tmp1], -tmp / 2});update(son[x][cnt], x, tmp);dfs1(y.first, x);cnt++;}} }int main() {int n;int x, y, z;scanf("%d", &n);for (int i = 1; i < n; i++) {scanf("%d%d%d", &x, &y, &z);adde(x, y, z);}for (int i = 1; i <= n; i++) {if(G[i].size() == 2) {printf("NO\n");return 0;}}for (int i = 1; i <= n; i++) {if(G[i].size() == 1) {root = i;break;}}dfs(root, -1);dfs1(root, -1);printf("YES\n");printf("%d\n", ans.size());for (int i = 0; i < ans.size(); i++) {printf("%d %d %lld\n", ans[i].x, ans[i].y, ans[i].z);} }

第二種用了類似樹剖中重兒子的思想,我們給一顆子樹中決定一個優先級最高的葉子結點,這樣加的操作是這個葉子結點到它的祖先的路徑上進行的,其它的路徑沒有影響,這樣累加影響的時候,如果這個葉子結點,把前面的影響累加上,否則不加。復雜度O(n)。

代碼:

#include <bits/stdc++.h> #define pii pair<int, int> #define LL long long using namespace std; const int maxn = 1010; vector<pii> G[maxn]; vector<int> son[maxn]; LL add[maxn]; struct node {int x, y;LL z; }; vector<node> ans; int root = 1; int v[maxn]; void adde(int x, int y, int z) {G[x].push_back(make_pair(y, z));G[y].push_back(make_pair(x, z)); }int dfs(int x, int fa) {for (auto y : G[x]) {if(y.first== fa) continue;int tmp = dfs(y.first, x);son[x].push_back(tmp);}if(G[x].size() == 1) {v[x] = x;return x;}v[x] = son[x][0];return son[x][0]; }void dfs1(int x, int fa, int tot) {int cnt = 0;if(x == root) {int y = G[x][0].first;if(G[y].size() == 1) {ans.push_back((node){x, y, G[x][0].second});return;}LL tmp = G[x][0].second;ans.push_back((node){son[y][0], root, tmp / 2});ans.push_back((node){son[y][1], root, tmp / 2});ans.push_back(node{son[y][0], son[y][1], -tmp / 2});dfs1(y, x, 0);} else {for (auto y : G[x]) {if(y.first == fa) continue;LL tmp = y.second;if(v[y.first] == v[x]) tmp -= tot;int tmp1;if(cnt == 0) tmp1 = 1;else tmp1 = 0;ans.push_back((node){son[x][cnt], root, tmp / 2});ans.push_back((node){son[x][cnt], son[x][tmp1], tmp / 2});ans.push_back(node{root, son[x][tmp1], -tmp / 2});dfs1(y.first, x, y.second);cnt++;}} }int main() {int n;int x, y, z;scanf("%d", &n);for (int i = 1; i < n; i++) {scanf("%d%d%d", &x, &y, &z);adde(x, y, z);}for (int i = 1; i <= n; i++) {if(G[i].size() == 2) {printf("NO\n");return 0;}}for (int i = 1; i <= n; i++) {if(G[i].size() == 1) {root = i;break;}}dfs(root, -1);dfs1(root, -1, 0);printf("YES\n");printf("%d\n", ans.size());for (int i = 0; i < ans.size(); i++) {printf("%d %d %lld\n", ans[i].x, ans[i].y, ans[i].z);} }

兩份代碼中為了實現方便,都找了一個度為1的點為根。

?

轉載于:https://www.cnblogs.com/pkgunboat/p/11145961.html

總結

以上是生活随笔為你收集整理的Codeforces 1188A 构造的全部內容,希望文章能夠幫你解決所遇到的問題。

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