HDU 4467 块状结构

56 篇文章 0 订阅
1 篇文章 0 订阅


题意很简单。就是两个操作

1、要么翻转某个点的标号。

2、要么询问某组边的权值一共为多少,总共有三种类型的边:端点分别为(0, 0), (0, 1), (1, 1)。


显然暴力超时。。这时候就用到了块状性质。

假设度数 >  Sqrt(m) 的节点为重节点,  度数 <= Sqrt(m) 的节点为轻节点。。


可以知道 重节点数 <=  Sqrt(m) ,  轻节点暴力修改时复杂度为 Sqrt(m)


修改操作:

如果是轻节点, 暴力修改周围节点, 如果周围节点有 重节点,就维护该值 , 复杂度 O(sqrt(m))

如果是重节点 ,   只用维护与它相连的重节点,可知重节点不超过O(sqrt(m)), 复杂度O(sqrt(m))


查询操作:

      直接输出答案  O(1)


#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <sstream>
#include <math.h>

#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i = j; i < k;i++)

#define MAX(x,a)  x=((x)<(a))?(a):(x);
#define MIN(x,a)  x=((x)>(a))?(a):(x);

using namespace std;

int Sqrt = 333;
const int N = 100210;
int n,m,q;
map<pii ,long long>M;
int is[N],a[N],wei[500000];
int ne[500000],to[500000];
long long g[700][700];
int head[N];
int deg[N];
int tot,cnt;
long long f[800][4];
long long ans[10];

void addedge(int u,int v,int w){
    ne[tot] = head[u],to[tot]=v, wei[tot] = w , head[u] = tot++;
}
void init(){
    Sqrt = (int)sqrt(1.0*m);
    M.clear();
    cnt = tot = 0;
    memset(g,0,sizeof(g));
    memset(is,0xff,sizeof(is));
    memset(head,0xff,sizeof(head));
    memset(ans,0,sizeof(ans));
    memset(f,0,sizeof(f));
    memset(deg,0,sizeof(deg));
    rep(i,0,n) scanf("%d",a+i);
    rep(i,0,m){
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w); u--,v--;
        if(u>v)swap(u,v);
        ans[a[u]+a[v]] += w;
        if(M.count(mp(u,v))) M[mp(u,v)]+=w;
        else{
            M[mp(u,v)]+=w;
            deg[u]++,deg[v]++;
        }
    }
    rep(i,0,n){
        if(deg[i]>Sqrt) 
            is[i] = cnt++;
    }
}
void deal(){
    map<pii , long long>::iterator it = M.begin();
    for( ; it != M.end(); it++){
        int u = it->first.first , v = it->first.second;
        if(~is[u] && ~is[v]){ // 都是度数>Sqrt的
            g[is[u]][is[v]] += it->second;
            g[is[v]][is[u]] += it->second;
            f[is[u]][a[v]] += it->second;
            f[is[v]][a[u]] += it->second;
        }else if(~is[u]){    // u 是
            f[is[u]][a[v]] += it->second;
            addedge(v,u,it->second);
        }else if(~is[v]){    // v 是
            f[is[v]][a[u]] += it->second;
            addedge(u,v,it->second);
        }else{
            addedge(u,v,it->second);
            addedge(v,u,it->second);
        }
    }
}
void modify(int u){
    if(~is[u]){ // 是 重度数
		ans[a[u]] -= f[is[u]][0] , ans[1-a[u]] += f[is[u]][0];
		ans[1+a[u]] -= f[is[u]][1] , ans[2-a[u]] += f[is[u]][1];
		rep(i,0,cnt)
			f[i][a[u]] -= g[is[u]][i] , f[i][1-a[u]] += g[is[u]][i];
    }else{    // 不是重度数
        for(int i = head[u] ; i != -1; i = ne[i]){
            int v = to[i] , w = wei[i];
            if(~is[v]){
                f[is[v]][a[u]] -= w;
                f[is[v]][1-a[u]] += w;
            }
            ans[a[u]+a[v]] -= w;
            ans[1-a[u]+a[v]] += w;
        }
    }
    a[u] ^= 1;
}
int main(){
    int tt = 0;
    while(scanf("%d %d",&n,&m)!=EOF){
        init();
        deal();
        scanf("%d",&q);
        char op[20]; int l,r;
        printf("Case %d:\n",++tt);
        while(q--){
            scanf("%s",op);
            if(op[0] == 'A'){
                scanf("%d %d",&l,&r);
                printf("%I64d\n",ans[l+r]);
            }else{
                scanf("%d",&l); l--;
                modify(l);
            }
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值