標籤:des style java color strong os
專案管理Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 252 Accepted Submission(s): 88
Problem Description我們建造了一個大項目!這個項目有n個節點,用很多邊串連起來,並且這個項目是連通的!
兩個節點間可能有多條邊,不過一條邊的兩端必然是不同的節點。
每個節點都有一個能量值。
現在我們要編寫一個專案管理軟體,這個軟體呢有兩個操作:
1.給某個項目的能量值加上一個特定值。
2.詢問跟一個項目相鄰的項目的能量值之和。(如果有多條邊就算多次,比如a和b有2條邊,那麼詢問a的時候b的權值算2次)。
Input第一行一個整數T(1 <= T <= 3),表示測試資料的個數。
然後對於每個測試資料,第一行有兩個整數n(1 <= n <= 100000)和m(1 <= m <= n + 10),分別表示點數和邊數。
然後m行,每行兩個數a和b,表示a和b之間有一條邊。
然後一個整數Q。
然後Q行,每行第一個數cmd表示操作類型。如果cmd為0,那麼接下來兩個數u v表示給項目u的能量值加上v(0 <= v <= 100)。
如果cmd為1,那麼接下來一個數u表示詢問u相鄰的項目的能量值之和。
所有點從1到n標號。
Output對每個詢問,輸出一行表示答案。
Sample Input
13 21 21 360 1 150 3 41 11 30 2 331 2
Sample Output
41515
思路:如果直接暴力,原則上是要TLE的,可惜這題資料比較水~下面說說我的解法每個點維護兩個值,w[i]-該點的值、sum[i]-相鄰節點值的和。怎樣在複雜度較小的範圍內維護這兩個值呢。如果把與x相連的點分為兩類,一類的度數大於它(該類不超過(2m)^(1/2)),另一類度數小於它。更新和查詢時時只操作度數大於它的點,就能降低複雜度了。
一個點更新時度數大於它的相鄰點是直接更新了的,查詢大點時答案已經統計了,但是查詢小點的時候答案這沒有統計完,對於小點,這個點又為小點的大點,於是再遍曆一下,將未更新的點更新維護sum數組即可。
複雜度就為 q*sqrt(m)了。還有注意要將重邊合并。
代碼:
#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#define maxn 100005#define MAXN 300005using namespace std;int n,m,ans,cnt,tot;int head[maxn],dug[maxn];int sum[maxn],w[maxn];struct node{ int u,v,num;} edge[MAXN];struct Node{ int v,next,num,last;} g[MAXN];void addedge(int u,int v,int num){ cnt++; g[cnt].v=v; g[cnt].num=num; g[cnt].next=head[u]; head[u]=cnt;}bool cmp(node xx,node yy){ if(xx.u!=yy.u) return xx.u<yy.u ; if(xx.v!=yy.v) return xx.v<yy.v;}int main(){ int i,j,t,u,v; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1; i<=n; i++) dug[i]=head[i]=w[i]=sum[i]=0; for(i=1; i<=m; i++) { scanf("%d%d",&u,&v); if(u>v) swap(u,v); edge[i].u=u; edge[i].v=v; edge[i].num=1; } sort(edge+1,edge+m+1,cmp); tot=1; for(i=2; i<=m; i++) // 合并相同邊 { if(edge[i].u==edge[tot].u&&edge[i].v==edge[tot].v) edge[tot].num++; else edge[++tot]=edge[i]; } for(i=1; i<=tot; i++) // 計算度數 { dug[edge[i].u]++; dug[edge[i].v]++; } cnt=0; for(i=1; i<=tot; i++) // 點與相鄰節點度數較大的點建圖 { u=edge[i].u; v=edge[i].v; if(dug[v]>dug[u]) addedge(u,v,edge[i].num); else addedge(v,u,edge[i].num); } int q,op,val; scanf("%d",&q); while(q--) { scanf("%d",&op); if(op==0) { scanf("%d%d",&u,&val); w[u]+=val; for(i=head[u]; i; i=g[i].next) // 更新大點的sum值 { v=g[i].v; sum[v]+=g[i].num*val; } } else { scanf("%d",&u); ans=sum[u]; for(i=head[u]; i; i=g[i].next) // 計算未更新的大點的值 { v=g[i].v; if(g[i].last!=w[v]) { ans+=g[i].num*(w[v]-g[i].last); g[i].last=w[v]; } } sum[u]=ans; printf("%d\n",ans); } } } return 0;}