hdu 4467 Graph

题意:给出n个点,m条边,每个点都有一个颜色,黑色(用1表示)或白色(用0表示)。有两种操作,一种是询问所有边中满足边的两个点是00,01 or 11这三种情况的边的权值的和,另一种是修改某一点的颜色。

思路:这一题最直观的思路就是暴力,查询简单,用一个数组预处理三种情况的边就能在O(1)的时间内完成了,修改一个点u的话,再遍历所有与u相连的点,把数组更新就好了。但是这样还是有问题的,由于m比较大,最坏的情况,修改一个点的时间复杂的有可能高达O(m),这样明显是不行的。为了减少这种情况的出现,我们要进行一些优化,简单的来说,就是把度数非常大的点单独挑出来,然后额外处理这些点,其他点还是暴力搞。那么挑哪些点才合适呢?其实只要选择那些度数>sqrt(m)的点就行了,因为这些点的个数不会超过2*sqrt(m),这个数不会超过700,所以每次操作不会超过700,还是可以接受的。这里证明一下吧,设度数大于sqrt(m)的点的个数为cnt,则cnt*sqrt(m)<=m*2,所以cnt<=sqrt(m)*2。处理这些度数大的点可以用一个数组a[i][j]记录每两个点之间的距离(如果没有边设成0就好了),用sum[i][0]和sum[i][1]分别记录与这个点相连的边中另一个顶点为白(黑)色点的总权值。最后只要注意一下处理重边就行了,重边要合并在一起,不然会添加不必要的节点,会超时。

 

代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#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=100000+10;
struct Edge
{
    int u,v,next;
    ll w;
};
Edge edges[maxn<<1];
int head[maxn],nEdge;
int n,m;
int color[maxn],degree[maxn];
ll a[700][700],sum[700][2];
ll res[3];
int hash[maxn],spnt;
void AddEdge(int u,int v,int w)
{
    nEdge++;
    edges[nEdge].u=u;
    edges[nEdge].v=v;
    edges[nEdge].w=w;
    edges[nEdge].next=head[u];
    head[u]=nEdge;
}
void Init()
{
    memset(head,0xff,sizeof(head));
    memset(degree,0,sizeof(degree));
    memset(hash,0,sizeof(hash));
    memset(res,0,sizeof(res));
    nEdge=-1;spnt=0;
}
void precal()
{
    int lim=(int)sqrt((double)m);
    for(int i=1;i<=n;++i)
    {
        if(degree[i]>lim)
        {
            spnt++;
            hash[i]=spnt;
        }
    }
    memset(a,0,sizeof(a));
    memset(sum,0,sizeof(sum));
    int u,v;
    for(int i=0;i<nEdge;i+=2)
    {
        u=edges[i].u;v=edges[i].v;
        if(color[u]^color[v])
          res[2]+=edges[i].w;
        else if(color[u])
          res[1]+=edges[i].w;
        else res[0]+=edges[i].w;
        if(hash[u]&&hash[v])
        {
            a[hash[u]][hash[v]]+=edges[i].w;
            a[hash[v]][hash[u]]+=edges[i].w;
        }
        if(hash[u]) sum[hash[u]][color[v]]+=edges[i].w;
        if(hash[v]) sum[hash[v]][color[u]]+=edges[i].w;
    }
}
void change(int x)
{
    if(hash[x])
    {
        if(color[x])
        {
            res[0]+=sum[hash[x]][0];
            res[2]+=sum[hash[x]][1];
            res[2]-=sum[hash[x]][0];
            res[1]-=sum[hash[x]][1];
        }
        else
        {
            res[1]+=sum[hash[x]][1];
            res[2]+=sum[hash[x]][0];
            res[2]-=sum[hash[x]][1];
            res[0]-=sum[hash[x]][0];
        }
        for(int i=1;i<=spnt;++i)
        {
            if(i==hash[x]) continue;
            sum[i][color[x]]-=a[i][hash[x]];
            sum[i][color[x]^1]+=a[i][hash[x]];
        }
        color[x]^=1;
    }
    else
    {
        int v;
        for(int k=head[x];k!=-1;k=edges[k].next)
        {
            v=edges[k].v;
            if(color[x])
            {
                if(color[v]) res[2]+=edges[k].w,res[1]-=edges[k].w;
                else res[0]+=edges[k].w,res[2]-=edges[k].w;
            }
            else
            {
                if(color[v]) res[1]+=edges[k].w,res[2]-=edges[k].w;
                else res[2]+=edges[k].w,res[0]-=edges[k].w;
            }
            if(hash[v])
            {
                sum[hash[v]][color[x]]-=edges[k].w;
                sum[hash[v]][color[x]^1]+=edges[k].w;
            }
        }
        color[x]^=1;
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int tcase=0;
    int q;
    char str[10];
    map<ll,int>mp;
    while(~scanf("%d%d",&n,&m))
    {
        tcase++;
        Init();
        mp.clear();
        for(int i=1;i<=n;++i)
          scanf("%d",&color[i]);
        int u,v,w,id;
        ll tmp;
        for(int i=0;i<m;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            if(u>v) swap(u,v);
            tmp=(ll)u*100000+v;
            if(!mp[tmp])
            {
                degree[u]++;degree[v]++;
                AddEdge(u,v,w);
                AddEdge(v,u,w);
                mp[tmp]=nEdge;
            }
            else
            {
                id=mp[tmp];
                edges[id].w+=w;
                edges[id^1].w+=w;
            }
        }
        precal();
        printf("Case %d:\n",tcase);
        scanf("%d",&q);
        int a,b;
        while(q--)
        {
            scanf("%s",str);
            if(str[0]=='A')
            {
                scanf("%d%d",&a,&b);
                if(a^b) printf("%I64d\n",res[2]);
                else printf("%I64d\n",res[a]);
            }
            else
            {
                scanf("%d",&a);
                change(a);
            }
        }
    }
    return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值