题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4467

题意:给定n个点m条边的无向图,点被染色(黑0/白1),边带边权。然后q个询问。询问分为两种: Change u:把点u的颜色反转(黑变白,白变黑),Asksum a b(a,b的值为0/1):统计所以边的权值和,边的两个点满足一个点的颜色为a,一个点的颜色为b。

思路:考虑暴力的做法。修改可以做法O(1),但是查询就得O(m).所以总复杂度为O(m*q)会TLE。然后考虑图分块。参考HDU 4858的做法,将点分为重点和轻点。重点(度数>=sqrt(m)),轻点(度数sqrt(m))。 由于此题查询比较大,所以需要预处理一下优化之后的运算。我们定义每个顶点维护3个属性:顶点的颜色color,与该点相连的边并且另外一个点是白点的边权和W, 同理B是黑色点的边权和。 然后维护3个变量ansWW:边上两个点都是白色的边权和。同理ansWB,ansBB。

修改:

轻点更新自己的color,W,B。同时更新所有的邻点的W,B值

重点更新自己的color,W,B。同时只更新相邻重点的W,B值(所以重点不需要连边到轻点)

对于更新。若未更新时该点的颜色为白色,那么更新后该点的颜色为黑色。那么对于相邻的点的W就要减去对应边的权值,相邻点的B就要加上对应边的权值。

对于更新。若未更新时该点的颜色为白色,那么更新后该点的颜色为黑色。那么边为WW的答案就要减去与该点相连的W的总和,边WB的答案就要减去与该点相邻的B的总和。  并且边为BB的答案就要加上与该点相邻的B的总和,边为WB的答案就要加上与该点相邻的W的总和。

查询:

直接输出对应的值

性质:

与重点相邻的重点不超过sqrt(m)个。

与轻点相邻的所有点不超过sqrt(m)个。

注意:

该题会有重边,如果不合并重边的话会TLE。所以用个map来合并下重边的值即可。

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<queue>
#include<math.h>
#include<time.h>
#include<vector>
#include<iostream>
#include<map>
using namespace std;
typedef long long int LL;
const int MAXN = 100000 + 10;
struct Edges{int u, v; LL w;Edges(int u = 0, int v = 0,LL w=0) :u(u), v(v),w(w){};
};vector<Edges>G[MAXN];
map<pair<int, int>, LL>edge;
struct Node{int val;LL W, B;Node(int val = 0, LL W = 0, LL B = 0) :val(val), W(W), B(B){};
}node[MAXN];
LL ansWB, ansWW, ansBB;
int du[MAXN], block;
void init(int n,int m){edge.clear(); ansWB = ansWW = ansBB = 0;block = (int)sqrt(m + 0.5);for (int i = 1; i <= n; i++){G[i].clear(); du[i] = 0; node[i].W = node[i].B = 0;}
}
void makeGraph(int n, int m){for (map<pair<int,int>,LL>::iterator it=edge.begin(); it!=edge.end(); it++){int u = it->first.first, v = it->first.second; LL w = it->second;if (du[u] >= block&&du[v] >= block){G[u].push_back(Edges(u, v, w)); G[v].push_back(Edges(v, u, w));}if (du[u] < block){G[u].push_back(Edges(u, v, w));}if (du[v] < block){G[v].push_back(Edges(v, u, w));}if (node[u].val&&node[v].val){ansWW += w; node[u].W += w; node[v].W += w;}else if (!node[u].val&&!node[v].val){ansBB += w; node[u].B += w; node[v].B += w;}else{ansWB += w; if (node[u].val){node[u].B += w; node[v].W += w;}else{node[u].W += w; node[v].B += w;}}}
}
void modify(int pos){if (node[pos].val){ansWW -= node[pos].W; ansWB -= node[pos].B;ansBB += node[pos].B; ansWB += node[pos].W;for (int i = 0; i < G[pos].size(); i++){node[G[pos][i].v].W -= G[pos][i].w;node[G[pos][i].v].B += G[pos][i].w;}}else{ansBB -= node[pos].B; ansWB -= node[pos].W;ansWW += node[pos].W; ansWB += node[pos].B;for (int i = 0; i < G[pos].size(); i++){node[G[pos][i].v].W += G[pos][i].w;node[G[pos][i].v].B -= G[pos][i].w;}}node[pos].val = !node[pos].val;
}
LL query(int u, int v){if (u&&v){ return ansWW; }if (!u&&!v){ return ansBB; }return ansWB;
}
int main(){//#ifdef kirito//    freopen("in.txt", "r", stdin);//    freopen("out.txt", "w", stdout);//#endifint n, m, q,Case=1;while (~scanf("%d%d", &n, &m)){init(n, m);for (int i = 1; i <= n; i++)scanf("%d", &node[i].val);for (int i = 1; i <= m; i++){int u, v; LL w; scanf("%d%d%I64d", &u, &v, &w);if (u > v){ swap(u, v); }if (edge.find(make_pair(u, v)) == edge.end()){du[u]++; du[v]++;edge.insert(make_pair(make_pair(u, v), w));}else{edge[make_pair(u, v)] += w;}}makeGraph(n, m);printf("Case %d:\n", Case++);scanf("%d", &q);while (q--){int u,v;  char type[20];scanf("%s", type);if (type[0]=='A'){scanf("%d%d", &u, &v);printf("%I64d\n", query(u, v));}else{scanf("%d", &u); modify(u);}//Debug:printf("BB=%I64d WB=%I64d WW=%I64d\n", ansBB, ansWB, ansWW);
        }}return 0;
}

转载于:https://www.cnblogs.com/kirito520/p/5952863.html

HDU 4467 分块相关推荐

  1. HDU 2920 分块底数优化 暴力

    其实和昨天写的那道水题是一样的,注意爆LL $1<=n,k<=1e9$,$\sum\limits_{i=1}^{n}(k \mod i) = nk - \sum\limits_{i=1}^ ...

  2. B - Paint The Wall HDU - 4391[分块hash+tag标记]

    题目大意:就是有两个第一个操作你可以修改[l,r]区间内的所有数称为z,第二个操作是问你[l,r]区间内z的个数是多少 解法1:分块 由于这里涉及到了区间修改那么我们要借助线段树的Tag的思想,对于没 ...

  3. HDU 5919 分块做法

    题意和链接前面的blog有,就不再提.. 思路:本来实在是莽不过去..后来想到其实复杂度均摊下来每块取比sqrt(n)大一些更好..具体大多少..嗯..大概x^2/logx=N  .?我也不会解... ...

  4. HDU多校1 - 6959 zoto(莫队+树状数组/值域分块)

    题目链接:点击查看 题目大意:在二维平面内有 nnn 个点,表示为 (i,f[i])(i,f[i])(i,f[i]),需要回答 mmm 次询问,每次询问会给出一个矩形,问矩形内有多少个不同的 yyy ...

  5. HDU 6555 The Fool(打表整除分块)

    HDU 6555 The Fool(打表&整除分块) 1.打表,找规律.发现是3-5-7-然后等差数列求和特判即可. 2.整除分块,复杂度O(n)O(\sqrt{n})O(n​) code l ...

  6. 树上分块 - Successor HDU - 4366

    题目大意:就是给你一颗树[上司和下属的对应关系],每个人都有一个忠诚度和能力值,下面有m次询问,每次你要解雇一个人[删除一个节点],问你这个人下属[子树]中是否有比这个人能力值大的,如果有找出忠诚度最 ...

  7. HDU多校1 - 6756 Finding a MEX(分块+二分+树状数组)

    题目链接:点击查看 题目大意:给出一个 n 个点和 m 条边的无向图,每个点都有一个权值,现在需要执行 q 次操作,每次操作分为两种类型: 1 pos val :将第 pos 个点的权值修改为 val ...

  8. HDU - 6959 zoto 莫队 + 值域分块

    传送门 文章目录 题意: 思路: 题意: 给你nnn个数,每个数有个值,有mmm次询问,每次给定l,r,y1,y2l,r,y1,y2l,r,y1,y2代表查询[l,r][l,r][l,r]区间内在[y ...

  9. 数论分块练习([CF830 C]Bamboo Partition + [hdu 6395]Sequence )

    文章目录 T1:Sequence title solution T2:Bamboo Partition title solution code T1:Sequence title 传送 solutio ...

最新文章

  1. 医学影像设备学_【技士/师证考试宝典】第四篇 医学影像设备学2
  2. 解决Sublime Text打开C++文件出现中文乱码
  3. LiveVideoStackCon 2021北京站 9月再次启航!
  4. 同样的电器,为什么官网能比实体店的价格便宜那么多?
  5. mysql单表简单排序查询
  6. Cloudera Manager agent无法启动,拒绝链接 Failed! trying again in 2 second(s): [Errno 111] Connection refuse
  7. double free or corruption 错误解决办法
  8. Java企业面试算法新得体会之5字符串问题24问
  9. ES9新特性_ES9正则扩展-dotAll模式---JavaScript_ECMAScript_ES6-ES11新特性工作笔记056
  10. C++两种单例(饿汉式,懒汉式)
  11. heartbeat V2实现MySQL+NFS高可用
  12. 关于禁用html中a标签的思考
  13. 高通 SD卡驱动代码流程
  14. 《Mybatis 手撸专栏》第10章:使用策略模式,调用参数处理器
  15. (Django开发)免费HTML模板资源集合
  16. VS 配置Directx
  17. CVF 6.6B 安装无反应(响应)及打开无反应(响应)问题(win10系统)
  18. 百度云和ai开放平台关系_集成平台即服务,云和……独角兽
  19. Web渗透攻击之vega
  20. Class文件结构介绍[常量池],埃森哲java技术面试题

热门文章

  1. 全面分析再动手的习惯:链表的反转问题(递归和非递归方式)
  2. ny20 吝啬的国度
  3. 第一篇文章,做个纪念
  4. Swift2.x编写NavigationController动态缩放titleView
  5. 地图下载2之天超图瓦片格式
  6. Node.js服务器启用Gzip压缩
  7. Kinect for Windows V2 SDK+ VS2012 环境搭建
  8. 【实用总结】DOM节点className操作
  9. 项目构建之maven篇:2.HelloWorld项目构建过程
  10. HDU 4951 Multiplication table(2014 Multi-University Training Contest 8)