Hdu 4467 Graph(点分块)

传送门:Hdu 4467 Graph


题意:给你n个点,m条边,每条边有一个权值,有两个操作,一个是修改单点的颜色,一个是询问边的两个端点都为指定颜色的权值和


思路:
对点进行分块,度数大于等于根号n的点称为重点,
否则称为轻点
对于轻点,存下与其相连的所有的边,对于重点,只存下与这个重点相连的重点的边

对于一个点的更新,如果这个点是轻点,暴力更新与其相连的所有点
如果是重点,那么只需要更新与其相连的终点就可以了(因为如果连的是轻点,轻点更新的时候自然会更新这个点,而不会造成一条边的两个点都更新了,而这条边没有更新的情况)
对于与其相连的轻点,改变一下每个点记录的sum就可以了


#include<bits/stdc++.h>
using namespace std;
const int maxn=100100;
int color[maxn],degree[maxn],key[maxn];
struct Edge{
    int from,to;
    long long len;
}E[maxn*2];
vector<int>G[maxn];
vector<long long>c[maxn];
long long ans[3],sum[maxn][2];

bool cmp(Edge u,Edge v){
    if(u.from!=v.from)
        return u.from<v.from;
    return u.to<v.to;
}

char s[10];

void change(int u){
    if(key[u])
        for(int i=0;i<G[u].size();i++){
            sum[G[u][i]][color[u]]-=c[u][i];
            sum[G[u][i]][color[u]^1]+=c[u][i];
        }
    else{
        sum[u][0]=0,sum[u][1]=0;
        for(int i=0;i<G[u].size();i++){
            sum[u][color[ G[u][i] ]]+=c[u][i];
            if(key[ G[u][i] ]){
                sum[G[u][i]][color[u]]-=c[u][i];
                sum[G[u][i]][color[u]^1]+=c[u][i];
            }
        }
    }
    if(color[u]==0){
        ans[0]-=sum[u][0],ans[1]+=(sum[u][0]-sum[u][1]);
        ans[2]+=sum[u][1];
        color[u]^=1;
    }
    else{
        ans[0]+=sum[u][0],ans[1]+=(sum[u][1]-sum[u][0]);
        ans[2]-=sum[u][1];
        color[u]^=1;
    }
}

int main(){
    int n,m,case1=1;
    while(scanf("%d%d",&n,&m)!=EOF){
        printf("Case %d:\n",case1++);
        for(int i=1;i<=n;i++)
            scanf("%d",&color[i]),c[i].clear(),G[i].clear();
        int u,v;
        for(int i=1;i<=m;i++){
            scanf("%d%d%lld",&E[i].from,&E[i].to,&E[i].len);
            if(E[i].from>E[i].to)
                swap(E[i].from,E[i].to);
        }
        sort(E+1,E+m+1,cmp);
        int tot=0;
        E[++tot]=E[1];
        for(int i=2;i<=m;i++){
            if(E[tot].from==E[i].from&&E[i].to==E[tot].to)
                E[tot].len+=E[i].len;
            else
                E[++tot]=E[i];
        }
        memset(ans,0,sizeof(ans));
        memset(sum,0,sizeof(sum));
        memset(key,0,sizeof(key));
        memset(degree,0,sizeof(degree));
        for(int i=1;i<=tot;i++){
            degree[E[i].from]++,degree[E[i].to]++;
            sum[E[i].from][color[E[i].to]]+=E[i].len;
            sum[E[i].to][color[E[i].from]]+=E[i].len;
            ans[color[E[i].to]+color[E[i].from]]+=E[i].len;
        }
        int unit=sqrt(n);
        for(int i=1;i<=n;i++)
            if(degree[i]>unit)
                key[i]=1;
        for(int i=1;i<=tot;i++){
            u=E[i].from,v=E[i].to;
            if(key[u]&&key[v]){ //轻链存着所有边,重链只存重链
                G[u].push_back(v),c[u].push_back(E[i].len);
                G[v].push_back(u),c[v].push_back(E[i].len);
            }
            if(key[u]==0)
                G[u].push_back(v),c[u].push_back(E[i].len);
            if(key[v]==0)
                G[v].push_back(u),c[v].push_back(E[i].len);
        }
        int q;
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%s",s);
            if(s[0]=='C')
                scanf("%d",&u),change(u);
            else{
                scanf("%d%d",&u,&v);
                printf("%lld\n",ans[u+v]);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值