hdu 4467 Graph 阀值

来源:互联网 发布:素万上淘宝吗 编辑:程序博客网 时间:2024/05/02 08:22


Graph

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2885    Accepted Submission(s): 467


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 xth 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 ≤ 105), where n is the number of nodes and m is the number of edges.
The second line consists of n integers, the ith of which represents the color of the ith 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 ≤ 231 - 1) between u and v (u != v).
The next line contains only one integer q (1 ≤ q ≤ 105), 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 30 0 0 01 2 12 3 23 4 34Asksum 0 0Change 2Asksum 0 0Asksum 0 14 30 1 0 01 2 12 3 23 4 34Asksum 0 0Change 3Asksum 0 0Asksum 0 1
 

Sample Output
Case 1:633Case 2:304
 

Source
2012 Asia Chengdu Regional Contest
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  5551 5550 5549 5548 5547 



解题报告:

坑点放在最前面:有重边!!!!!!这个会导致一个点的颜色更改后,与之相邻的某个点的对应信息会被多次更改!!!


怎样使它不超时:
很容易想到,每个点维护一个一维数组sum[2],sum[0]表示与之相邻为白色点的边权和,sum[1]为与之相邻为黑色点的边权和。
对于整个图,维护一个一位数组ans[3],ans[1]代表变得两端分别是白色点的边权和,ans[1]两端一黑一白,ans[2]两端黑。

但是n、m最大1e5,查询次数最多1e5,
这么一来最极端的情况就是 1e5* 1e5=1e10,远远超时

今天看了别人的博客,又学习到了一个新方法:

首先我们要把点分为两类,一种是普通点,一种是超级点,每次更改点的颜色是,把这两种点区别对待,则可在规定时间内完成任务。

普通点:与之相邻的点数小于阀值upcase。

超级点:与之相邻的点数达到阀值upcase。

我们把阀值upcase定位 sqrt(m);

可以证明超级点的数量不超过2*sqrt(m):
若超过,则 边总数会超过 2*sqrt(m)*sqrt(m)/2=m;

假若对于超级点,处理一次发杂度为O(sqrt(m)),对于普通点处理一次复杂度也为O(sqrt(m)),那么总时间是O(query*sqrt(m)+query*sqrt(m))=O(query*sqrt(m))
就可以在规定时间内完成任务。

首先每个点要记录它是什么颜色。
那能不能做到呢?
1.
对于更改的超级点:
我们只用利用他的sum[0]和sum[1]来维护最终结果,并且更改与之相邻不超过2*sqrt(m)个超级点的相关信息。
那么与之相邻的普通点呢?不用管它,不用更改与之相关的信息,为什么呢?看下面。
2.
对于更改的普通点:
我们暴力遍历它的相邻点,来维护ans[];因为它是普通点,所以与之相邻的点不超过sqrt(m)个。
因为是暴力遍历,所以根本不用维护这些普通点的sum值。

这样一来无论更改什么点,时间复杂度都是O(sqrt(m))级别。



#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<climits>#include<string>#include<algorithm>#include<queue>#include<set>#include<vector>#include<map>#include<stack>typedef long long ll;using namespace std;const int maxn=1e5+10;const int maxm=1e5+10;int upcase,n,m;ll ans[3];struct Node{    int cnt;    ll sum[2];    int color;}node[maxn];struct Edge{    int from,to;    ll w;    Edge(){}    Edge(int &from,int &to,ll &w):from(from),to(to),w(w){}    bool operator<(const Edge b)const    {        if(from!=b.from)  return from<b.from;        return to<b.to;    }};vector<Edge>edges;vector<int >G[maxn];vector<ll >W[maxn];void init(){    upcase=sqrt(m+0.5);    for(int i=1;i<=n;i++)        G[i].clear(),W[i].clear();    edges.clear();    ans[0]=ans[1]=ans[2]=0;}char s[12];void change(int x){    int &cx=node[x].color;    if(node[x].cnt<upcase)    {        for(int i=0;i<G[x].size();i++)        {            int &y=G[x][i];            int &cy=node[y].color;            ans[cx+cy] -=W[x][i];            ans[(cx^1)+cy]+=W[x][i];            node[y].sum[cx]-=W[x][i];            node[y].sum[cx^1]+=W[x][i];        }    }    else    {        ans[cx    +0]-=node[x].sum[0];        ans[(cx^1)+0]+=node[x].sum[0];        ans[cx    +1]-=node[x].sum[1];        ans[(cx^1)+1]+=node[x].sum[1];        for(int i=0;i<G[x].size();i++)        {            int &y=G[x][i];            int &cy=node[y].color;            node[y].sum[cx]-=W[x][i];            node[y].sum[cx^1]+=W[x][i];        }    }    cx^=1;//掉了这句话呀!!!!}inline void query(){    scanf("%s",s);    int x,y;    if(s[0]=='A')    {        scanf("%d%d",&x,&y);        printf("%lld\n",ans[x+y]);    }    else    {        scanf("%d",&x);        change(x);    }}bool vis[maxm];int main(){    int x,y,q,kase=0;ll w;    while(~scanf("%d%d",&n,&m))    {        init();        for(int i=1;i<=n;i++)        {            scanf("%d",&node[i].color);            node[i].sum[1]=node[i].sum[0]=0,node[i].cnt=0;        }        for(int i=0;i<m;i++)        {            scanf("%d%d%lld",&x,&y,&w);            if(x>y)  swap(x,y);            edges.push_back(Edge(x,y,w ) );//            node[x].cnt++,node[y].cnt++; 放这里绝错            int cx=node[x].color;            int cy=node[y].color;            node[x].sum[cy]+=w;            node[y].sum[cx]+=w;            ans[cy+cx]+=w;        }        sort(edges.begin(),edges.end() );        memset(vis,0,sizeof vis);        for(int i=0;i<m;i++)        {            Edge & e=edges[i];            int x=e.from;            int y=e.to;            if(i&&x==edges[i-1].from&&y==edges[i-1].to)            {                e.w+=edges[i-1].w;                vis[i-1]=1;            }        }        for(int i=0;i<m;i++)        {            if(vis[i])  continue;            Edge & e=edges[i];            int x=e.from;            int y=e.to;            node[x].cnt++,node[y].cnt++;        }        for(int i=0;i<m;i++)        {            if(vis[i])  continue;            Edge & e=edges[i];            int x=e.from;            int y=e.to;            ll w=e.w;            if(node[x].cnt>=upcase&&node[y].cnt>=upcase)            {                W[x].push_back(w);                G[x].push_back(y);                W[y].push_back(w);                G[y].push_back(x);            }            if(node[x].cnt<upcase) G[x].push_back(y),W[x].push_back(w);            if(node[y].cnt<upcase) G[y].push_back(x),W[y].push_back(w);        }        scanf("%d",&q);        printf("Case %d:\n",++kase);        for(int i=1;i<=q;i++)        {            query();        }    }}







0 0