本来以为过了...然后FST了...

吐槽:nmdGraph为什么不连通...

这题想法其实非常\(na\ddot{\imath}ve\),就是对于一个连通块先钦点一个点为根,颜色是\(1\),考虑到边权限制点权,可以做二分图染色,钦点连通块内的某个形如树形的边的子集是全部合法的,显然一棵树是一定有解的,对于此时的\(\min ,\max\)只需要看根节点的取值范围取\(\min ,\max\),对于图的话显然就是多了一些边,判断多的边两端节点是否同色,如果同色则意味着根节点的权值是唯一确定的,如果不是整数则无解,否则直接赋值重跑一遍计算\(ans\)即可,复杂度\(\mathcal{O}(n+m)\)。

因为代码是从FST的改过来的,memset其实会T,但是懒得改了,所以下面代码复杂度是假的,不过不影响正确性

#include<bits/stdc++.h>
#define yes printf("%lld %lld\n",ansa,ansb);exit(0)
#define no printf("NIE\n");exit(0)
#define int long long using namespace std; signed ch; void qread(int &xx){
xx=0;ch=getchar();
while(!isdigit(ch)){
ch=getchar();
}
while(isdigit(ch)){
xx=xx*10+ch-'0';
ch=getchar();
}
} const int N=5e5+5,M=6e6+6; int n,m,ans,ansa,ansb,p[N],vis[N]; int fir[N],nxt[M],to[M],edge[M],cntedge,col[N],c[N],cnt[3]; int mi[3]={0,0,0x3f3f3f3f},up[3]={0,0,0x3f3f3f3f}; void addedge(int u,int v,int w){
++cntedge;to[cntedge]=v;edge[cntedge]=w;nxt[cntedge]=fir[u];fir[u]=cntedge;
} namespace subtree{
queue<int>q;
void bfs(int u){
for(int now=fir[u],v;now;now=nxt[now]){
v=to[now];
if(col[v]){
continue;
}
c[v]=edge[now]-c[u];
col[v]=3-col[u];
++cnt[col[v]];
ans+=c[v];
mi[col[v]]=min(mi[col[v]],c[v]);
up[col[v]]=min(up[col[v]],p[v]-c[v]);
q.push(v);
}
}
void solve(){
q.push(1);col[1]=1;++cnt[1];up[1]=p[1];
while(!q.empty()){
int u=q.front();q.pop();
bfs(u);
}
if(up[1]+up[2]<0){
no;
}
if(up[1]<0){
for(int i=1;i<=n;i++){
col[i]==1?(c[i]+=up[1],ans+=up[1]):(c[i]-=up[1],ans-=up[1]);
}
up[2]+=up[1];mi[2]-=up[1];mi[1]+=up[1];up[1]=0;
}
if(up[2]<0){
for(int i=1;i<=n;i++){
col[i]==2?(c[i]+=up[2],ans+=up[2]):(c[i]-=up[2],ans-=up[2]);
}
up[1]+=up[2];mi[1]-=up[2];mi[2]+=up[2];up[2]=0;
}
if(mi[1]+up[2]<0||mi[2]+up[1]<0||mi[1]+mi[2]<0){
no;
}
if(mi[1]<0){
for(int i=1;i<=n;i++){
col[i]==1?c[i]-=mi[1],ans-=mi[1]:c[i]+=mi[1],ans+=mi[1];
}
up[2]+=mi[1];mi[2]+=mi[1];up[1]+=mi[1];mi[1]=0;
}
else if(mi[2]<0){
for(int i=1;i<=n;i++){
col[i]==2?c[i]-=mi[2],ans-=mi[2]:c[i]+=mi[2],ans+=mi[2];
}
up[1]+=mi[2];mi[1]+=mi[2];up[2]+=mi[2];mi[2]=0;
}
if(cnt[1]==cnt[2]){
ansa=ansb=ans;
}
else if(cnt[1]<cnt[2]){
ansa=ans-min(mi[2],up[1])*(cnt[2]-cnt[1]);
ansb=ans+min(mi[1],up[2])*(cnt[2]-cnt[1]);
}
else{
ansa=ans-min(mi[1],up[2])*(cnt[1]-cnt[2]);
ansb=ans+min(mi[2],up[1])*(cnt[1]-cnt[2]);
}
yes;
}
} namespace qwq{
queue<int>q;
int s,id=0;bool flag;
bool check(){
while(!q.empty()){
q.pop();
}
memset(col,0,sizeof col);
q.push(s);col[s]=1;ans=c[s];
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=id;
if(c[u]<0||c[u]>p[u]){
no;
}
for(int now=fir[u],v;now;now=nxt[now]){
v=to[now];
if(col[v]){
if(c[u]+c[v]!=edge[now]){
no;
}
continue;
}
c[v]=edge[now]-c[u];
col[v]=3-col[u];
ans+=c[v];
q.push(v);
}
}
ansa+=ans;ansb+=ans;
return 1;
}
void bfs(int u){
vis[u]=id;
for(int now=fir[u],v;now;now=nxt[now]){
v=to[now];
if(col[v]){
if(col[u]^col[v]){
if(c[u]+c[v]!=edge[now]){
no;
}
}
else{
if(((c[u]+c[v])&1)^(edge[now]&1)){
no;
}
if(col[u]^2){
c[s]=(edge[now]-c[u]-c[v])>>1;
if(check()){
flag=1;return;
}
else{
no;
}
}
else{
c[s]=(c[u]+c[v]-edge[now])>>1;
if(check()){
flag=1;return;
}
else{
no;
}
}
}
continue;
}
c[v]=edge[now]-c[u];
col[v]=3-col[u];
++cnt[col[v]];
ans+=c[v];
mi[col[v]]=min(mi[col[v]],c[v]);
up[col[v]]=min(up[col[v]],p[v]-c[v]);
q.push(v);
}
}
void work(){
while(!q.empty()){
q.pop();
}
flag=0;
memset(cnt,0,sizeof cnt);
up[2]=mi[2]=0x3f3f3f3f;mi[1]=0;
q.push(s);col[s]=1;++cnt[1];up[1]=p[s];ans=0;
while(!q.empty()){
int u=q.front();q.pop();bfs(u);
}
if(flag){
return;
}
if(up[1]+up[2]<0){
no;
}
if(up[1]<0){
for(int i=1;i<=n;i++){
if(vis[i]!=id){
continue;
}
col[i]==1?(c[i]+=up[1],ans+=up[1]):(c[i]-=up[1],ans-=up[1]);
}
up[2]+=up[1];mi[2]-=up[1];mi[1]+=up[1];up[1]=0;
}
if(up[2]<0){
for(int i=1;i<=n;i++){
if(vis[i]!=id){
continue;
}
col[i]==2?(c[i]+=up[2],ans+=up[2]):(c[i]-=up[2],ans-=up[2]);
}
up[1]+=up[2];mi[1]-=up[2];mi[2]+=up[2];up[2]=0;
}
if(mi[1]+up[2]<0||mi[2]+up[1]<0||mi[1]+mi[2]<0){
no;
}
if(mi[1]<0){
for(int i=1;i<=n;i++){
if(vis[i]!=id){
continue;
}
col[i]==1?c[i]-=mi[1],ans-=mi[1]:c[i]+=mi[1],ans+=mi[1];
}
up[2]+=mi[1];mi[2]+=mi[1];up[1]+=mi[1];mi[1]=0;
}
else if(mi[2]<0){
for(int i=1;i<=n;i++){
if(vis[i]!=id){
continue;
}
col[i]==2?c[i]-=mi[2],ans-=mi[2]:c[i]+=mi[2],ans+=mi[2];
}
up[1]+=mi[2];mi[1]+=mi[2];up[2]+=mi[2];mi[2]=0;
}
if(cnt[1]==cnt[2]){
ansa+=ans;ansb+=ans;
}
else if(cnt[1]<cnt[2]){
ansa+=ans-min(mi[2],up[1])*(cnt[2]-cnt[1]);
ansb+=ans+min(mi[1],up[2])*(cnt[2]-cnt[1]);
}
else{
ansa+=ans-min(mi[1],up[2])*(cnt[1]-cnt[2]);
ansb+=ans+min(mi[2],up[1])*(cnt[1]-cnt[2]);
}
}
void solve(){
for(int i=1;i<=n;i++){
if(!vis[i]){
++id;s=i;
work();
}
}
yes;
}
} signed main(){
qread(n);qread(m);
for(int i=1;i<=n;i++){
qread(p[i]);
}
for(int i=1,u,v,w;i<=m;i++){
qread(u);qread(v);qread(w);addedge(u,v,p[u]+p[v]-w);addedge(v,u,p[u]+p[v]-w);
}
if(n==m+1){
subtree::solve();
}
else{
qwq::solve();
}
no;
return 0;
}

最新文章

  1. 前端编辑工具之VSCode
  2. 一个Woker类,当id和name相同时,系统判断两个工人是相等的,打印工人对象时显示“工人:id和name”。
  3. 关于IIS部署时出现“System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本”的问题解决摘要
  4. 【SPOJ QTREE2】QTREE2 - Query on a tree II(LCA)
  5. 【转载】uclibc和glibc的差别
  6. C#学习笔记三: C#2.0泛型 可控类型 匿名方法和迭代器
  7. 新浪云(SAE)使用没有内置的django版本
  8. 谷歌(Chrome)安装Advanced REST Client插件
  9. Cell的重用机制
  10. Hql 执行CRUD
  11. eclipse 打开文件目录
  12. 给Object扩展新方法
  13. 用erlang写的kmp算法
  14. springCloud项目练习
  15. Android为TV端助力:(转载)修改TextView字体样式
  16. jdk 动态代理的原理
  17. React JSX基本语法规则
  18. jdk下载--操作系统
  19. win下php的memcached的安装与使用
  20. Executor、ExecutorService、ThreadPoolExecutor

热门文章

  1. Centos7下yum安装kubernetes
  2. C++中类中常规变量、const、static、static const(const static)成员变量的声明和初始化
  3. PTA --- 天梯赛 L1-028 判断素数
  4. 【POJ - 3187】Backward Digit Sums(搜索)
  5. 【机器学习理论】概率论与数理统计--假设检验,卡方检验,t检验,F检验,方差分析
  6. elasticsearch的备份和恢复(转)
  7. HDU 1284 钱币兑换问题 (动态规划 背包方案数)
  8. Redis缓存击穿
  9. 2019中山纪念中学夏令营-Day2[JZOJ]
  10. HTTPS原理(三次握手)