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

题意是给你一个无向图,已知连接到每一个点的边的权值和(为整数,且属于区间[-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. kail linux arp欺骗

    首先连接wifi,进入内网 1,查看内网的存活主机  命令  fping -asg 192.168.1.0/24    (视不同环境而定,假设这里的路由器地址为 192.168.1.1) 也可利用其他 ...

  2. kali linux 基本命令(第一批)

    pwd  ,  rm    ,locate    ,cat    ,head     ,  clear    ,ls      ,cd     ,mkdir      ,touch       ,ec ...

  3. djago 定义后台地址

    在app 中urls.py 可替换原始后台登陆地址  /admin   为自定义地址

  4. uva 1633 Dyslexic Gollum

    题意: 给出n和k,求出长度为n的不包含长度大于等于k的回文串的01字符串的个数. 思路: 如果一个字符串包含长度为k的回文串,那么它肯定包含长度为k-1的回文串,所以考虑第i位的时候,只要前缀中不包 ...

  5. GJP_Project

    1. view层作用: 视图层,即项目中的界面 l  controller层作用: 控制层, 获取界面上的数据,为界面设置数据; 将要实现的功能交给业务层处理 l  service层作用: 业务层, ...

  6. notepad 正则表达式 复制 文本

  7. C#使用SmtpClient发送邮件

    目的:写一个可发送邮件的DLL. 原理: 例如A使用163邮箱发送邮件给B(qq邮箱).首先A会把邮件通过SMTP(Simple Mail Transfer Protocol)协议传输到163的Smt ...

  8. java课上测试心得

    放暑假之前,建民老师就给我们布置了每一天学习两小时的代码,但是自己的不重视,根本就没有达到这个要求,简单学了一点点基本的东西,然后在开学的第一堂课上,连续三个小时的敲代码,让我意识到了自己的问题,一个 ...

  9. css实现16:9的图片比例

    摘自:https://www.cnblogs.com/caizhenbo/p/css.html 需求: 最近产品要求不管原图的大小是多少,宽度一定,高度要自自适应为16:9. 分析: 对于正常的固定好 ...

  10. Kali linux apt-get update 失败,无release……(最有效)

    设置源 编辑 /etc/apt/sources.list nano /etc/apt/sources.list 清空文件内所有内容后添加 deb http://mirrors.ustc.edu.cn/ ...