HDU 4467 Graph (莫隊思想+圖的分塊)*
阿新 • • 發佈:2018-12-09
題目連結:acm.hdu.edu.cn/showproblem.php?pid=4467
#include<bits/stdc++.h> using namespace std; #define debug puts("YES"); #define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++) #define read(x,y) scanf("%d%d",&x,&y) #define ll long long #define lrt int l,int r,int rt #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const int maxn =2e5+5; const int mod=1e9+7; /* 題目大意:給定一個圖,每個點都有0,1值, 然後每個邊都有個權重值,給定q個查詢或者修改操作, 查詢是給定兩個數x,y要求輸出所有邊的權重和,邊滿足兩端權值相加為x+y。 修改是修改一個點的權值. 分塊的題目都有一種矛盾的意思在裡面, 比方說我們暴力一發,一個想法是對於每個點都維護一個sum陣列, 每次修改直接通過sum陣列的改變來更新答案陣列。 另一種想法是不維護sum陣列,直接暴力遍歷修改答案。 兩種方法都過不了,那麼直接兩種結合起來,分塊的題目我們一定要找到 一個指標,這個指標直接影響了複雜度,那麼通過觀察上面兩種做法, 可以知道這個指標就是點的度數,那麼我們依靠點的度數對點進行劃分, 重點與輕點。 對於重點,每次修改直接通過sum陣列更新答案,然後暴力更新相鄰重點的sum陣列, 輕點則直接暴力掃描所有相鄰點,然後更新答案。 這樣複雜度就被均攤了,因為重點的數量不超過m^(1/2)的性質。 我這份程式碼時間複雜度超了,下面的第二版是AC的,我 自己寫的不知道為什麼會一直過不了,希望大神指點。 */ ///資料域 int n,m,x,y; ll z; char s[20]; ll sum[maxn][2],a[3];///重點的統計陣列,分別表示i重點,相鄰的權重為0,1,2的邊權重和. vector<pair<int,ll>> hey[maxn];///重點和重點相連 ///點的結構 struct tp { int u,v; ll w;///邊和權重 bool operator==(const tp&y) const { return (u==y.u&&v==y.v)||(u==y.v&&v==y.u); } bool operator<(const tp& y) const { if(y.u==u) return v<y.v; return u<y.u; } }jihe[maxn]; ///鏈式前向星 struct node { int u,nxt; ll w; }edge[maxn<<1]; int head[maxn],tot=0; void init() { memset(a,0,sizeof(a)); tot=0; } void add(int x,int y,ll z) { edge[tot]=node{y,head[x],z}; head[x]=tot++; } ///權值陣列和度數陣列和是否為重點的判別陣列 int v[maxn],q; ll d[maxn],is_heavy[maxn]; int main() { int ca=1,ub; while(scanf("%d%d",&n,&m)!=EOF) { init(); for(int i=0;i<=n;i++) { d[i]=is_heavy[i]=0; sum[i][0]=sum[i][1]=0; hey[i].clear(); memset(head,-1,sizeof(head)); } for(int i=1;i<=n;i++) scanf("%d",&v[i]); for(int i=1;i<=m;i++) { scanf("%d%d%lld",&x,&y,&z); jihe[i].u=x,jihe[i].v=y,jihe[i].w=z; a[v[x]+v[y]]+=1LL*z; } ///去除多餘的重複邊 sort(jihe+1,jihe+m+1); int top=1; for(int i=2;i<=m;i++) { for(int j=i;j<=m&&(jihe[j]==jihe[top]);j++) jihe[top].w+=jihe[j].w; jihe[++top]=jihe[i]; } ub=sqrt(top); ///建邊,建度 for(int i=1;i<=top;i++) { int u=jihe[i].u,v=jihe[i].v; ll w=jihe[i].w; add(u,v,w),add(v,u,w); d[u]++,d[v]++; /* if(d[u]>=ub&&d[v]>=ub) { hey[u].push_back(make_pair(v,w)); hey[v].push_back(make_pair(u,w)); } */ } ///建重點圖並初始化sum集合 for(int i=1;i<=top;i++) { int u=jihe[i].u,v=jihe[i].v; ll w=jihe[i].w; if(d[u]>=ub&&d[v]>=ub) { hey[u].push_back(make_pair(v,w)); hey[v].push_back(make_pair(u,w)); } } for(int i=1;i<=n;i++) { if(d[i]>=ub)///標記為重點 { is_heavy[i]=1; for(int j=head[i];~j;j=edge[j].nxt) { int u=edge[j].u; sum[i][v[u]]+=edge[j].w; } } } scanf("%d",&q); printf("Case %d:\n",ca++); for(int i=0,tx,ty;i<q;i++) { scanf("%s",s); if(s[0]=='A') { scanf("%d%d",&tx,&ty); printf("%lld\n",a[tx+ty]); } else { scanf("%d",&tx); if(is_heavy[tx])///如果是重點,通過預處理好的陣列來更新 { a[v[tx]+0]-=sum[tx][0]; a[v[tx]+1]-=sum[tx][1]; a[1-v[tx]+1]+=sum[tx][1]; a[1-v[tx]+0]+=sum[tx][0]; for(int j=0;j<hey[tx].size();j++) { ll tp=hey[tx][j].first,tw=hey[tx][j].second; sum[tp][v[tx]]-=tw; sum[tp][1-v[tx]]+=tw; } v[tx]^=1; } else///輕點 { for(int j=head[tx];~j;j=edge[j].nxt) { int y=edge[j].u; if(is_heavy[y])///輕點和重點相連 { a[v[y]+v[tx]]-=1LL*edge[j].w; sum[y][v[tx]]-=1LL*edge[j].w; v[tx]^=1; sum[y][v[tx]]+=1LL*edge[j].w; a[v[y]+v[tx]]+=1LL*edge[j].w; } else///這種情況直接修改 { a[v[tx]+v[y]]-=1LL*edge[j].w; v[tx]^=1; a[v[tx]+v[y]]+=1LL*edge[j].w; } } } } } } return 0; } /* 4 4 0 0 0 0 1 2 1 2 3 2 3 4 3 1 2 1 */
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; typedef long long ll; const ll maxn=1e5+10; ll sum[maxn][2],a[5],color[maxn],du[maxn]; bool ok[maxn]; struct Edge{ ll x,y,val; }arr[maxn],arr_[maxn]; struct edge{ ll v,val; edge(ll _v=0,ll _val=0):v(_v),val(_val) {} }; vector<edge>G[maxn],G_[maxn]; bool cmp(Edge x,Edge y) { if ( x.x==y.x ) return x.y<y.y; return x.x<y.x; } int main() { ll n,m,i,j,k,x,y,z,sz,cnt,q,ans,h=0; char op[10]; while ( scanf("%lld%lld",&n,&m)!=EOF ) { for ( i=1;i<=n;i++ ) { sum[i][0]=sum[i][1]=0; ok[i]=false; du[i]=0; G[i].clear(); G_[i].clear(); } memset(a,0,sizeof(a)); for ( i=1;i<=n;i++ ) scanf("%lld",&color[i]); for ( i=1;i<=m;i++ ) { scanf("%lld%lld%lld",&x,&y,&arr[i].val); if ( x>y ) swap(x,y); arr[i].x=x; arr[i].y=y; a[color[x]+color[y]]+=arr[i].val; } sort(arr+1,arr+1+m,cmp); cnt=0; for ( i=1;i<=m;i=j ) { for ( j=i+1;j<=m;j++ ) { if ( arr[i].x==arr[j].x && arr[i].y==arr[j].y ) { arr[i].val+=arr[j].val; } else break; } arr_[++cnt]=arr[i]; } sz=sqrt(cnt); for ( i=1;i<=cnt;i++ ) { du[arr_[i].x]++; du[arr_[i].y]++; } for ( i=1;i<=n;i++ ) { if ( du[i]>sz ) ok[i]=true; } for ( i=1;i<=cnt;i++ ) { x=arr_[i].x; y=arr_[i].y; if ( ok[x] ) { if ( ok[y] ) { G_[x].push_back(edge(y,arr_[i].val)); G_[y].push_back(edge(x,arr_[i].val)); sum[x][color[y]]+=arr_[i].val; sum[y][color[x]]+=arr_[i].val; } else { G[y].push_back(edge(x,arr_[i].val)); sum[x][color[y]]+=arr_[i].val; } } else { if ( ok[y] ) { G[x].push_back(edge(y,arr_[i].val)); sum[y][color[x]]+=arr_[i].val; } else { G[x].push_back(edge(y,arr_[i].val)); G[y].push_back(edge(x,arr_[i].val)); } } } printf("Case %lld:\n",++h); scanf("%lld",&q); while ( q-- ) { scanf("%s",op); if ( op[0]=='A' ) { scanf("%lld%lld",&x,&y); printf("%lld\n",a[x+y]); } else { scanf("%lld",&x); if ( ok[x] ) { a[color[x]+0]-=sum[x][0]; a[color[x]+1]-=sum[x][1]; a[1-color[x]+0]+=sum[x][0]; a[1-color[x]+1]+=sum[x][1]; for ( i=0;i<G_[x].size();i++ ) { y=G_[x][i].v; z=G_[x][i].val; sum[y][color[x]]-=z; sum[y][1-color[x]]+=z; } } else { for ( i=0;i<G[x].size();i++ ) { y=G[x][i].v; z=G[x][i].val; a[color[x]+color[y]]-=z; a[1-color[x]+color[y]]+=z; if ( ok[y] ) { sum[y][color[x]]-=z; sum[y][1-color[x]]+=z; } } } color[x]=1-color[x]; } } } return 0; } HDOJ4467