zoj 3742 Bellywhite's Algorithm Homework

题意:给出一个无向图,n个点m条边,有一些操作:Q +  查询所有正边和        Q -   查询所有负边和         Q A  查询所有边和        C  X  把跟X邻接的边的权值取反。

思路:这题还是蛮经典的,和hdu 4467 Graph挺像的。就是把顶点度数大于sqrt(m)的点单独拿出来处理,其他的点直接暴力修改。用两个值存所有正边和所有负边的和,修改特殊点的时候,只修改和它相连的也是特殊点之间的边的值,和可以通过维护sum[i][2]算出,这个数组是表示和这个特殊点相连的点的边的正边和负边的和。另外用filp[i]标记这个点,当普通点去修改和它相邻的边时,可以通过两个顶点的filp值来得到当前边的正负……


代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=50000+10;
struct Edge
{
    int u,v,next;
    int w;
    Edge (){};
    Edge(int uu,int vv,int ww,int nx) {u=uu;v=vv;w=ww;next=nx;}
}edges[maxn<<1];
int head[maxn],nEdge;
int n,m,q,filp[maxn],degree[maxn];
ll a[555][555][2],sum[555][2];
ll res[2];
int hash[maxn],cnt;
void AddEdge(int u,int v,int w)
{
    edges[++nEdge]=Edge(u,v,w,head[u]);
    head[u]=nEdge;
}
void Init()
{
    memset(head,0xff,sizeof(head));
    memset(degree,0,sizeof(degree));
    memset(hash,0,sizeof(hash));
    memset(filp,0,sizeof(filp));
    res[0]=res[1]=0;
    nEdge=-1;cnt=0;
}
void precal()
{
    int lim=(int)sqrt((double)m);
    for(int i=1;i<=n;++i)
    {
        if(degree[i]>lim)
        {
            hash[i]=++cnt;
        }
    }
    memset(a,0,sizeof(a));
    memset(sum,0,sizeof(sum));
    int u,v;
    for(int i=0;i<nEdge;i+=2)
    {
        if(edges[i].w>0) res[0]+=edges[i].w;
        else res[1]+=edges[i].w;
        u=edges[i].u;v=edges[i].v;
        if(hash[u]&&hash[v])
        {
            if(edges[i].w>0)
            {
                a[hash[u]][hash[v]][0]+=edges[i].w;
                a[hash[v]][hash[u]][0]+=edges[i].w;
            }
            else
            {
                a[hash[u]][hash[v]][1]+=edges[i].w;
                a[hash[v]][hash[u]][1]+=edges[i].w;
            }
        }
        if(hash[u]) sum[hash[u]][edges[i].w<0]+=edges[i].w;
        if(hash[v]) sum[hash[v]][edges[i].w<0]+=edges[i].w;
    }
}
void changes(int x)
{
    if(hash[x])
    {
        res[0]+=(-sum[hash[x]][1]);
        res[0]-=sum[hash[x]][0];
        res[1]+=(-sum[hash[x]][0]);
        res[1]-=sum[hash[x]][1];

        swap(sum[hash[x]][0],sum[hash[x]][1]);
        sum[hash[x]][0]*=-1;sum[hash[x]][1]*=-1;
        for(int i=1;i<=cnt;++i)
        {
            if(i==hash[x]) continue;
            sum[i][0]-=a[i][hash[x]][0];
            sum[i][0]+=(-a[i][hash[x]][1]);
            sum[i][1]-=a[i][hash[x]][1];
            sum[i][1]+=(-a[i][hash[x]][0]);
            swap(a[i][hash[x]][0],a[i][hash[x]][1]);
            a[i][hash[x]][0]*=-1;a[i][hash[x]][1]*=-1;
            swap(a[hash[x]][i][0],a[hash[x]][i][1]);
            a[hash[x]][i][0]*=-1;a[hash[x]][i][1]*=-1;
        }
        filp[x]^=1;
    }
    else
    {
        int v,tmp;
        filp[x]^=1;
        for(int k=head[x];k!=-1;k=edges[k].next)
        {
            v=edges[k].v;
            if(filp[x]^filp[v]) tmp=-edges[k].w;
            else tmp=edges[k].w;
            if(tmp>0)
            {
                res[0]+=tmp;
                res[1]-=(-tmp);
                if(hash[v])
                {
                    sum[hash[v]][0]+=tmp;
                    sum[hash[v]][1]-=(-tmp);
                }
            }
            else
            {
                res[0]-=(-tmp);
                res[1]+=tmp;
                if(hash[v])
                {
                    sum[hash[v]][0]-=(-tmp);
                    sum[hash[v]][1]+=tmp;
                }
            }
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    char str[5];
    //map<ll,int>mp;
    int first=true;
    while(~scanf("%d%d%d",&n,&m,&q))
    {
        if(!first) printf("\n");
        first=false;
        Init();
        //mp.clear();
        int u,v,w;
        for(int i=0;i<m;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            degree[u]++;degree[v]++;
            AddEdge(u,v,w);
            AddEdge(v,u,w);
            //mp[tmp]=nEdge;
        }
        precal();
        ll ans=0;
        int x;
        while(q--)
        {
            scanf("%s",str);
            if(str[0]=='Q')
            {
                scanf("%s",str);
                if(str[0]=='A')
                    ans=res[0]+res[1];
                else if(str[0]=='+')
                    ans=res[0];
                else ans=res[1];
                printf("%lld\n",ans);
            }
            else
            {
                scanf("%d",&x);
                changes(x);
            }
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值