前言:结论题似乎是我的硬伤……

题意是给你一个无向图,已知连接到每一个点的边的权值和(为整数,且属于区间[-n,n]),需要求出每条边权值的一个合法解(都要是在区间[-2*n^2,2*n^2]内的整数)。

第一个想法当然是O(n^2*m)的高斯消元。在此基础上,我想过通过选取某些节点,在边权总和中减去与之相邻的边,来逐个解出边的权值。这个本质上是优化解方程的办法难以适应全部情况,且难以通过编程实现。于是只能舍弃这个想法。

后来通过漫无边际的瞎想,观察标题,容易发现对于一棵树求解这个问题是极为容易的。于是下一个思路就是把这个无向图转化为一棵树。如下图所示,偶环的情况是很容易就能解决的。(无脑删边)

那么奇环怎么办呢?事实上,本人就卡在了这里。如果按照偶环的方法来解释奇环删边的合法性,我们发现最终有一个点的点权增加了2a。陷入僵局。这时,不妨让我们再考虑一下对树求解的过程。也就是一次dfs,对于除根结点之外的每一个结点都满足其权值和,再根据根结点是否满足其约束条件来判断是否有解。注意到上面奇环的操作,实质就意味着如果我们以一个奇环上的点为根结点,那么就可以在最后判断的时候任意加上一个偶数了。容易证明,最后与根结点相邻的边权和与其应有的边权和之差一定是一个偶数。也就是说,有奇环的图是一定有解的。因此,我们如上的处理奇环的方式,并不会影响解的存在性。

于是,我们就得到了处理环的方式:都不鸟它,并从奇环上随意拉一个点当根结点。

讲到这里,我们似乎还忽略了一个条件。

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

当然,这个范围是相当大的,一般而言解是一定在这个区间内的(也仅限一般而言)。基于cf是一个有hack机制的网站,毫无疑问会有数据把你的解卡出这个区间(对本人而言是test 34)。因此,random_shuffle是必不可缺的

时间复杂度O(n+m)。

 #include <bits/stdc++.h>
#define int long long
#define tag(i) (ed[((i)|1)>>1].id)
using namespace std;
const int N = ;
struct edge {
int la,b;
edge(int la=,int b=):la(la),b(b) {};
} con[N<<];
int tot=,fir[N];
void add(int from,int to) {
con[++tot] = edge(fir[from],to);
fir[from] = tot;
con[++tot] = edge(fir[to],from);
fir[to] = tot;
}
int c[N],ans[N],n,m,cnt,dep[N],rt,ano,fat[N],up[N],mar[N];
typedef pair<int,int> pii;
struct data {
int a,b,id;
data(int a=,int b=,int id=):a(a),b(b),id(id){}
} ed[N];
pii ext[N];
bool vis[N];
void dfs_init(int pos,int fa) {
fat[pos] = fa;
vis[pos] = ;
dep[pos] = dep[fa] + ;
for (int i = fir[pos] ; i ; i = con[i].la) {
if (con[i].b == fa) continue;
if (vis[con[i].b]) {
if (pos > con[i].b) ext[++cnt] = pii(pos,i);
} else dfs_init(con[i].b,pos),up[con[i].b] = tag(i);
}
}
int dfs(int pos,int fa) {
vis[pos] = ;
int now = c[pos];
for (int i = fir[pos] ; i ; i = con[i].la) {
if (vis[con[i].b]) continue;
now -= (ans[tag(i)] = dfs(con[i].b,pos));
}
return now;
}
bool ocy(pii x) {
int a = x.first, b = con[x.second].b;
return (dep[a] + dep[b] + )&;
}
void print() {
puts("YES");
for (int i = ; i <= m ; ++ i) {
cout << ans[i] << endl;
}
}
void modify(int x,int y) {
int k1 = , k2 = -;
while (dep[x] > dep[y]) {
mar[up[x]] += k1;
k1 = -k1;
x = fat[x];
}
while (dep[y] > dep[x]) {
mar[up[y]] += k2;
k2 = -k2;
y = fat[y];
}
while (x != y) {
mar[up[x]] += k1;
k1 = -k1;
x = fat[x];
mar[up[y]] += k2;
k2 = -k2;
y = fat[y];
}
}
signed main() {
int a,b;
cin >> n >> m;
for (int i = ; i <= n ; ++ i) cin>>c[i];
for (int i = ; i <= m ; ++ i) {
cin >> a >> b;
ed[i] = data(a,b,i);
}
random_shuffle(ed+,ed+m+);
for (int i = ; i <= m ; ++ i) add(ed[i].a,ed[i].b);
dfs_init(,);
for (int i = ; i <= cnt ; ++ i) {
if (ocy(ext[i])) {
rt = ext[i].first, ano = con[ext[i].second].b;
modify(rt,ano);
mar[tag(ext[i].second)] ++;
break;
}
}
memset (vis,,sizeof vis);
if (rt) {
int uns = dfs(rt,)>>;
for (int i = ; i <= m ; ++ i) ans[i] += mar[i] * uns;
print();
} else {
if (dfs(,) != ) puts("NO");
else print();
}
return ;
}

小结:关于我卡在奇环无从下手,应该是缺乏与实际算法的运行相结合。

【做题】Codeforces Round #453 (Div. 1) D. Weighting a Tree——拆环的更多相关文章

  1. Codeforces Round #453 (Div. 1) D. Weighting a Tree(构造)

    题意 一个 \(n\) 个点 \(m\) 条边的无向连通图中每个点都有一个权值,现在要求给每条边定一个权值,满足每个点的权值等于所有相连的边权之和,权值可负. 题解 如果图是一棵树,那么方案就是唯一的 ...

  2. Codeforces Round #453 (Div. 1)

    Codeforces Round #453 (Div. 1) A. Hashing Trees 题目描述:给出一棵树的高度和每一层的节点数,问是否有两棵树都满足这个条件,若有,则输出这两棵树,否则输出 ...

  3. 水题 Codeforces Round #308 (Div. 2) A. Vanya and Table

    题目传送门 /* 水题:读懂题目就能做 */ #include <cstdio> #include <iostream> #include <algorithm> ...

  4. 水题 Codeforces Round #302 (Div. 2) A Set of Strings

    题目传送门 /* 题意:一个字符串分割成k段,每段开头字母不相同 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 */ #include <cstdio> ...

  5. 水题 Codeforces Round #299 (Div. 2) A. Tavas and Nafas

    题目传送门 /* 很简单的水题,晚上累了,刷刷水题开心一下:) */ #include <bits/stdc++.h> using namespace std; ][] = {" ...

  6. 水题 Codeforces Round #304 (Div. 2) A. Soldier and Bananas

    题目传送门 /* 水题:ans = (1+2+3+...+n) * k - n,开long long */ #include <cstdio> #include <algorithm ...

  7. 水题 Codeforces Round #303 (Div. 2) A. Toy Cars

    题目传送门 /* 题意:5种情况对应对应第i或j辆车翻了没 水题:其实就看对角线的上半边就可以了,vis判断,可惜WA了一次 3: if both cars turned over during th ...

  8. 水题 Codeforces Round #286 (Div. 2) A Mr. Kitayuta's Gift

    题目传送门 /* 水题:vector容器实现插入操作,暴力进行判断是否为回文串 */ #include <cstdio> #include <iostream> #includ ...

  9. 构造水题 Codeforces Round #206 (Div. 2) A. Vasya and Digital Root

    题目传送门 /* 构造水题:对于0的多个位数的NO,对于位数太大的在后面补0,在9×k的范围内的平均的原则 */ #include <cstdio> #include <algori ...

随机推荐

  1. C++中overload(重载),override(覆盖),overwrite(重写/覆写)的区别

    #include <cstdio> #include <cstdlib> class Base { public: #pragma region MyRegion1 //函数重 ...

  2. html5-样式表的使用-初步

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  3. Java集合-----List详解

    List中的元素是有序排列的而且可重复 1.LinkedList LinkedList是非线程安全的,底层是基于双向链表实现的       LinkedList常用方法:     toArray()  ...

  4. ★★★kalinux 常用命令

    1.修改密码: sudo  passwd  root 2.重启:reboot ====================================== arch 显示机器的处理器架构(1) una ...

  5. string 常量池 栈 堆

  6. OpenVPN 服务端(pritunl)的一些运维经验

    1.当服务端部署在docker中,重启机器之后,docker服务会启动,pritunl的docker容器也会跟着自动启动.但此时,一些系统服务还未完全启动成功,导致会有一些pritunl server ...

  7. Linux基础命令---init进程

    init init是所有进程的父进程,它由内核执行,可以启动其他所有的进程.init指令在启动时会参考/etc/inittab文件的配置,完成其他进程的启动.init通常不会由用户进程执行,并且期望进 ...

  8. JustOj 1386: 众数的数量

    题目链接:http://oj.jxust.edu.cn/problem.php?id=1386 题目描述 qwn和Q伟N最近沉迷于Battle of Balls,天天翘课玩游戏.因为Q伟N太坑了,所以 ...

  9. DNS缓存中毒的知识

    网络上出现互联网漏洞——DNS缓存漏洞,此漏洞直指我们应用中互联网脆弱的安全系统,而安全性差的根源在于设计缺陷.利用该漏洞轻则可以让用户无法打开网页,重则是网络钓鱼和金融诈骗,给受害者造成巨大损失. ...

  10. MFC超链接

    最近写一个小的对话框程序时,想加一个文本超链接,研究了一下,发上自己的研究成果,供大家参考.下面说说完整的步骤. (假定静态文本ID为ID_STATIC) 首先,设置鼠标的形状及响应鼠标点击 第一步, ...