BZOJ3135: [Baltic2013]pipes

138 篇文章 0 订阅

正常解法要高斯消元,由于数据范围太大,考虑换个思路
每条边是一个未知数,每个点是一个方程,各联通块之间不影响,所以每个联通块单独考虑那么可知
当n< m时,未知数比方程多,一定多解或无解
当n> m-1时,图一定不连通的,所以不会有这种情况
于是m-1<=n<=m,就可以树形DP辣

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 110000;
const int maxm = 510000;

struct edge
{
    int y,nex;
    edge(){}
    edge(int _y,int _nex){y=_y;nex=_nex;}
}a[maxm<<1]; int len,fir[maxn];
ll ve[maxm<<1],ans[maxm],v[maxn];
int n,m,e[maxm][2];
void ins(int x,int y){ a[++len]=edge(y,fir[x]); fir[x]=len; }

int fa[maxn];
int find_(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find_(fa[x]);
}

bool vis[maxn];
int bel[maxn];
int cnt,tot[maxn],etot[maxn];

int t[maxn],tp,cir[maxn],cn,cid[maxn];
bool ev[maxn];
bool f_cir(int x,int fr)
{
    if(ev[x])
    {
        int la=0;
        while(la!=x)
        {
            la=t[tp--];
            cir[++cn]=la;
            cid[la]=cn;
        }
        return true;
    }
    ev[x]=true;
    t[++tp]=x;
    for(int k=fir[x];k;k=a[k].nex)
        if(a[k].y!=fr) 
            if(f_cir(a[k].y,x))return true;
    tp--;
    return false;
}
void sear(int x,int fr,int pre)
{
    for(int k=fir[x];k;k=a[k].nex)
    {
        int y=a[k].y;
        if(y!=fr&&!cid[y]) sear(y,x,k);
        v[x]-=ve[k]>>1;
    }
    if(pre) ve[pre]=ve[pre^1]=v[x]<<1,v[x]=0;
}

int main()
{
    len=1; memset(fir,0,sizeof fir);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld",&v[i]),fa[i]=i;

    for(int i=1;i<=m;i++)
    {
        int x,y; scanf("%d%d",&x,&y);
        fa[find_(y)]=find_(x);
        ins(x,y); ins(y,x);
        e[i][0]=x; e[i][1]=y;
    }
    cnt=0;
    for(int i=1;i<=n;i++)
    {
        int f1=find_(i);
        if(!bel[f1])
        {
            bel[i]=bel[f1]=++cnt;
            tot[cnt]=1;
        }
        else bel[i]=bel[f1],tot[bel[i]]++;
    }
    for(int i=1;i<=m;i++)
        etot[bel[e[i][0]]]++;

    memset(vis,false,sizeof vis);
    memset(ev,false,sizeof ev);
    for(int l=1;l<=n;l++)
    {
        int f1=find_(l);
        if(vis[f1]) continue;
        vis[f1]=true;
        f1=bel[f1];
        if(tot[f1]<etot[f1]) { printf("0\n"); return 0; }
        if(tot[f1]==etot[f1]) 
        {
            tp=cn=0;
            f_cir(l,0);
            if(cn%2==0) { printf("0\n"); return 0; }
            for(int j=1;j<=cn;j++)
                sear(cir[j],0,0);

            ll xc=0,sc=0;
            for(int i=1;i<=cn;i++) xc+=v[cir[i]];
            for(int i=2;i<cn;i+=2)
                sc+=v[cir[i]];
            sc=xc-sc*2;

            if(sc%2==1) { printf("0\n"); return 0; }
            for(int i=1,la=cir[cn];i<=cn;la=cir[i],i++)
            {
                for(int k=fir[cir[i]];k;k=a[k].nex)
                    if(a[k].y==la)
                    {
                        ve[k]=ve[k^1]=sc;
                        sc=2*(v[cir[i]]-sc/2);
                        break;
                    }
            }
        }
        else
        {
            sear(l,0,0);
            if(v[l]) { printf("0\n"); return 0; }
        }
    }
    for(int i=2;i<=len;i+=2) ans[i>>1]=ve[i];
    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值