博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hdu4467 Graph
阅读量:5084 次
发布时间:2019-06-13

本文共 5307 字,大约阅读时间需要 17 分钟。

Graph

Problem Description

P. T. Tigris is a student currently studying graph theory. One day, when he was studying hard, GS appeared around the corner shyly and came up with a problem:
Given a graph with n nodes and m undirected weighted edges, every node having one of two colors, namely black (denoted as 0) and white (denoted as 1), you’re to maintain q operations of either kind:
* Change x: Change the color of x
th node. A black node should be changed into white one and vice versa.
* Asksum A B: Find the sum of weight of those edges whose two end points are in color A and B respectively. A and B can be either 0 or 1.
P. T. Tigris doesn’t know how to solve this problem, so he turns to you for help.
 

 

Input
There are several test cases.
For each test case, the first line contains two integers, n and m (1 ≤ n,m ≤ 10
5), where n is the number of nodes and m is the number of edges.
The second line consists of n integers, the i
th of which represents the color of the i
th node: 0 for black and 1 for white.
The following m lines represent edges. Each line has three integer u, v and w, indicating there is an edge of weight w (1 ≤ w ≤ 2
31 - 1) between u and v (u != v).
The next line contains only one integer q (1 ≤ q ≤ 10
5), the number of operations.
Each of the following q lines describes an operation mentioned before.
Input is terminated by EOF.
 

 

Output
For each test case, output several lines.
The first line contains “Case X:”, where X is the test case number (starting from 1).
And then, for each “Asksum” query, output one line containing the desired answer.
 

 

Sample Input
4 3 0 0 0 0 1 2 1 2 3 2 3 4 3 4 Asksum 0 0 Change 2 Asksum 0 0 Asksum 0 1 4 3 0 1 0 0 1 2 1 2 3 2 3 4 3 4 Asksum 0 0 Change 3 Asksum 0 0 Asksum 0 1
 

 

Sample Output
Case 1: 6 3 3 Case 2: 3 0 4
这题是很好的题啊,题目意思就是,给一些点,都是0或1,找两边是00 01 11的边权合,这题的关键就是有的边很多,如果我们就用暴力,那么复杂度必然是p*n,其实,想想问题的关键,就是有的点相连的边太多了,这样暴力会超时,比赛的时候,也是这个问题,虽然有点想法,但当时由于时间太短,不能写出来,下来要想了很长时间,我们要把有很多的边标记下,特殊处理,这样,我们不就能省掉很多时间了么?基于,这样的想法,我们,就可以这样做,把超过界限的点,标记成超极点,其他的就是普通点,我们连接超极点和超极点,普通点与普通点。超极点,但是,超极点不连接普通点!对于超极点,我们用一个数组,保存它周围的0和1的点的权和,这样我们就可以用0(1)的时间,快速维护最终的结果,对于普通点,我们就暴力维护就可以了,因为他周围的点少,时间就可以大大的省下来!这样的想法很好,复杂度是多少呢?我们可以发现,如果我们把办限定为sqrt(m),那么超极点的个数一定不会多于2*sqrt(m),这一点很好证明,那么这样,所有点的暴力维护的值都是sqrt(m)了,那么复杂度就是n*sqrt(m),当然,这是可以过了的,这种思想很有用,也很神奇啊,当时,有点影子,但没有时间,来实现了!对于本题一定要注意重边的情况和一定要用--int64,好了,到这里,就可以a了!还有一点小技巧,见代码!
#include 
#include
#include
#include
#include
using namespace std;#define MAXN 100005struct nodeedge{ int s,e; __int64 val;}edge[40*MAXN];struct nodelist{ int next,to,flag;}l[200*MAXN];char str[300];int head[MAXN],p[MAXN],index[MAXN],limit;//判定是否是超极点__int64 sum[3],sumsuper[MAXN][2];void change(int x){ int i,j; int temp=p[x]^1,t; for(j=head[x];j!=-1;j=l[j].next) { i=l[j].to; sum[p[x]+p[i]]-=edge[j].val; sum[temp+p[i]]+=edge[j].val; if((!l[x].flag)&&l[i].flag) { sumsuper[i][p[x]]-=edge[j].val; sumsuper[i][temp]+=edge[j].val; } } if(l[x].flag) { sum[p[x]]-=sumsuper[x][0]; sum[temp]+=sumsuper[x][0]; sum[p[x]+1]-=sumsuper[x][1]; sum[temp+1]+=sumsuper[x][1]; } p[x]=p[x]^1;//取反}void build(int i,int s,int e,__int64 val)//建邻接表{ if(l[s].flag&&(!l[e].flag)) { sumsuper[s][p[e]]+=val; } else { l[i].next=head[s]; l[i].to=e; head[s]=i; }}bool cmp(nodeedge a,nodeedge b){ if(a.s != b.s) return a.s < b.s; else return a.e < b.e;}int main (){ int n,m,i,edgem,m2,asnum,a1,a2,tcase; tcase=1; while(scanf("%d%d",&n,&m)!=EOF) { limit=350;m2=2*m; sum[0]=sum[1]=sum[2]=0; for(i=1;i<=n;i++) { scanf("%d",&p[i]); index[i]=0;head[i]=-1; } for(i=1;i<=m;i++) { scanf("%d%d%I64d",&edge[i].s,&edge[i].e,&edge[i].val); edge[i+m].s=edge[i].e,edge[i+m].e=edge[i].s,edge[i+m].val=edge[i].val;//建反向边 sum[p[edge[i].s]+p[edge[i].e]]+=edge[i].val; } sort(edge+1,edge+m2+1,cmp);//边从1开始计数 edgem=1; for(i=2;i<=m2;i++)//去掉重边 { if((edge[i].s==edge[edgem].s)&&(edge[i].e==edge[edgem].e)) { edge[edgem].val+=edge[i].val; } else{ edgem++; edge[edgem]=edge[i]; } } for(i=1;i<=edgem;i++) { index[edge[i].s]++; } for(i=1;i<=n;i++)//统计超极结点 { if(index[i]>=limit) { l[i].flag=1;//是超极结点 sumsuper[i][0]=sumsuper[i][1]=0; } else l[i].flag=0; } for(i=1;i<=edgem;i++)//建领接表 { build(i,edge[i].s,edge[i].e,edge[i].val); } scanf("%d",&asnum); printf("Case %d:\n",tcase++); while(asnum--) { scanf("%s",str); if(str[0]=='A') { scanf("%d%d",&a1,&a2); printf("%I64d\n",sum[a1+a2]); } else{ scanf("%d",&a1); change(a1); } } } return 0;}

转载于:https://www.cnblogs.com/snake-hand/p/3211819.html

你可能感兴趣的文章
BZOJ4923 K小值查询(splay)
查看>>
被sleep开了个小玩笑
查看>>
centos安装memcache与telnet
查看>>
安卓ROOT后禁用/隐藏导航栏/虚拟按键
查看>>
day13 字典生成式
查看>>
将二维数组转为一维数组的2种方法
查看>>
使用1.7 Files,实现编码探测
查看>>
(二)快速搭建 ASP.net core Web 应用
查看>>
TopCoder-SRM635-DIV1-250pt-SimilarRatingGraph-枚举+边界处理
查看>>
轻松搞懂Python的属性和方法
查看>>
JVM内存状况查看方法和分析工具
查看>>
关于判断物体是否在视野范围内
查看>>
Android应用开发中模拟按HOME键效果
查看>>
Python:ModuleNotFoundError: No module named 'windows'
查看>>
Linq查询
查看>>
json_encode charset
查看>>
jquery api
查看>>
C#compiler
查看>>
machine%20learning
查看>>
JSON 简单例子
查看>>