hdu 4467 Graph ( 神奇的思想 降低複雜度 )

來源:互聯網
上載者:User
Graph

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 695    Accepted Submission(s): 113Problem DescriptionP. 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. 

InputThere 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. 

OutputFor 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
 

Source2012 Asia Chengdu Regional Contest題意:給一張無向圖,有n個點,m條邊,每個點2個狀態:0和1,每條邊有一個權值w,現在給q個操作。有2種操作,change x表示改變x點的狀態。asksum a,b表示查詢所有端點為a 和 b的邊的權值之和。
思路:這題很容易想到直接暴力解決 但資料量過大 複雜度為O(q*m)  肯定是得TLE的  q不能最佳化了  那麼只能最佳化m了   暴力的話每次都要對一個點的每條相鄰邊掃描一遍  太耗時了  於是要想一想能不能每次不遍曆所有相鄰邊呢?

重新分析一下此題:由於每個點只有0 1兩個狀態,那麼答案只有3種情況,用一個數組維護即可。即ans[0]統計邊的兩端都是0的權值和,ans[1]統計邊的兩端為1和0的權值總和,ans[2]統計邊的兩端都是1的權值和。這樣只要維護好這個數組,那麼對於查詢操作,可以O(1)的時間輸出。那麼關鍵就在change操作的維護了。

先說一個想法:如果記錄每個點與之相連的點顏色分別為0和1 的權值之和,以w0和w1來表示。那麼,該點改變時,例如:噹噹前點由0->1時,ans[0]-w[0],ans[1]+w[1],ans[2]-w[1]+w[0];  這樣就是O(1)複雜度了,而且當前點得出結果也是正確的。但是,當處理其他點時,其他點的w0和w1
沒有給到更新,這顯然是不行的,還需要再做些文章。

說到這裡,先說個結論,對於點x,與x相連並且度數大於x的度數的點不會超過 (2m)^(1/2),這個證明很好證,可以自己去推下。如果把與x相連的點分為兩類,一類的度數大於他(該類不超過(2m)^(1/2)),另一類度數小於他。對度數小於他的整體操作,度數大於他的逐邊操作,那麼就能降低複雜度了。接下來,我採取的方法是,用 w[x][0] (與x相連的邊的顏色為0)和 w[x][1] (與x相連的邊的顏色為1)表示度數比x節點小的權值之和,至於度數比它大,則逐邊進行處理,處理時更新w[y][0]、w[y][1]
(因為相對x而言,y是度數大的點,所以可以在對度數比它大的點逐邊枚舉時也可以更新w的資訊,一舉三得,因為還降低了複雜度)。這樣複雜度就可以降到 q*(m)^1/2 了。

最後,說下這種思想為什麼是正確的。對於點x,度數大於它的是逐邊處理的,ans可以直接更新;度數小於它的,資訊則沒有更新,那麼,當處理到那些度數小的點時,也是按同樣的方法在處理,度數大於的點逐邊處理,這不就是把以前沒有更新的過程給完成了嗎?這樣,就不會出現需要使用改點時,資訊沒得到完善。總而言之,就是利用度數將點分類,然後一部分整體處理,一部分枚舉。


感想:這種降低複雜度的思想真的太妙了,值得研究!啥時候能自己想出來就牛逼了。 嘻嘻

哦 對了 這題還要考慮重邊的情況,真的好沒意思,沒辦法,現場賽的題目就是各種位置都要坑你一下才行,我對那些哪些卡在重邊上的隊真的表示惋惜。


代碼:

// Exe.Time  1750MS   Exe.Memory   6104K   hdu暫居第五#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#define maxn 100005using namespace std;int n,m,cxx;int color[maxn];int deg[maxn];long long w[maxn][2],ww[2];long long ans[3];char s[50];struct Node{    int l,r;    long long val;} edge[maxn];int point[maxn];struct node      // 圖的鄰接表{    int r,next;    long long val;}side[maxn];bool cmp(const Node &x1,const Node &x2){    if(x1.l<x2.l) return true ;    else if(x1.l==x2.l) return x1.r<x2.r;    return false ;}void addedge(int u,int v,long long cost){    cxx++;    side[cxx].r=v;    side[cxx].val=cost;    side[cxx].next=point[u];    point[u]=cxx;}int main(){    int i,j,l,r,q,t=0,tmp,cnt,lc,nc;    long long temp;    while(~scanf("%d%d",&n,&m))    {        t++;        for(i=1; i<=n; i++)        {            scanf("%d",&color[i]);        }        ans[0]=ans[1]=ans[2]=0;        for(i=1; i<=m; i++)        {            scanf("%d%d%I64d",&edge[i].l,&edge[i].r,&edge[i].val);            ans[color[edge[i].l]+color[edge[i].r]]+=edge[i].val;        // 更新初始 ans            if(edge[i].l>edge[i].r)       // 保證 l<r 方便下面找重邊            {                temp=edge[i].l;                edge[i].l=edge[i].r;                edge[i].r=temp;            }        }        sort(edge+1,edge+m+1,cmp);        cnt=1;        for(i=2; i<=m; i++)    // 重邊合并        {            if(edge[i].l==edge[cnt].l&&edge[i].r==edge[cnt].r)            {                edge[cnt].val+=edge[i].val;            }            else            {                cnt++;                if(i!=cnt)                {                    edge[cnt].l=edge[i].l;                    edge[cnt].r=edge[i].r;                    edge[cnt].val=edge[i].val;                }            }        }        memset(deg,0,sizeof(deg));        for(i=1;i<=cnt;i++)          // 記錄各點的度數        {            deg[edge[i].l]++;            deg[edge[i].r]++;        }        cxx=0;        memset(point,0,sizeof(point));        memset(w,0,sizeof(w));        for(i=1;i<=cnt;i++)      // 對度數比他大的點 建立鄰接表        {            l=edge[i].l;            r=edge[i].r;            if(deg[l]<=deg[r])            {                w[r][color[l]]+=edge[i].val;   // 度數小的點沒有進鄰接表 則加入W[]數組內                addedge(l,r,edge[i].val);            }            else            {                w[l][color[r]]+=edge[i].val;                addedge(r,l,edge[i].val);            }        }        printf("Case %d:\n",t);        scanf("%d",&q);        while(q--)        {            scanf("%s",s);            if(s[0]=='A')            {                scanf("%d%d",&l,&r);                printf("%I64d\n",ans[l+r]);            }            else            {                scanf("%d",&r);                lc=color[r];                color[r]=!lc;                ww[0]=ww[1]=0;                for(i=point[r]; i ;i=side[i].next)      // 度數大的點進行處理                {                    ww[color[side[i].r]]+=side[i].val;                    if(lc)               // 對度數大的而言 r就是度數小的 需更新資訊                    {                        w[side[i].r][0]+=side[i].val;                        w[side[i].r][1]-=side[i].val;                    }                    else                    {                        w[side[i].r][0]-=side[i].val;                        w[side[i].r][1]+=side[i].val;                    }                }                if(lc)          // 一起更新ans                {                    ans[0]=ans[0]+ww[0]+w[r][0];                    ans[1]=ans[1]-ww[0]+ww[1]-w[r][0]+w[r][1];                    ans[2]=ans[2]-ww[1]-w[r][1];                }                else                {                    ans[0]=ans[0]-ww[0]-w[r][0];                    ans[1]=ans[1]+ww[0]-ww[1]+w[r][0]-w[r][1];                    ans[2]=ans[2]+ww[1]+w[r][1];                }            }        }    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.