https://vjudge.net/problem/HDU-6756
題目大意:給你一個無向圖,每個點有權值a,將f(u)定義為對u的鄰居的集合求mex;
有兩個操作:
1:將u的權值修改為x
2:查詢f(u)
數據量在1e5,可以考慮分塊,我們按照每個點的度數將點分為大小點,小于sqrt(n)的為小點,否則為大點。
先預處理分塊。
修改操作:
如果為小點,則直接修改他的所有鄰居
如果為大點,我們就先不修改他的鄰居,我們使用一個容器來記錄大點的鄰居(大點不會很多的)的當前貢獻,等到在查詢的時候,我們會先遍歷一遍大點的鄰居,如果鄰居當前的貢獻不等于鄰居現在的權值的話,說明該大點鄰居已經被修改過了,那么我們直接修改該鄰居的貢獻。
查詢操作:直接分塊查詢mex,先查詢每個快是不是滿了,不滿的話說明答案就在這個塊中。
?
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <cstdlib>
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(a) ((a)&-(a))
#define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
#define fi first
#define sc second
#define scd(a) scanf("%d",&a)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define ac cout<<ans<<"\n"
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
int dx[4]= {-1,1,0,0},dy[4]= {0,0,1,-1};
const ll mod=1e9+7;
const ll N =1e5+10;
const ll M =250000;
const double eps = 1e-4;
//const double pi=acos(-1);
ll qk(ll a,ll b){ll ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b/=2;}return ans%mod;}
int a[N],block_size=0;
vector<int> g[N];
vector<int>tag[N],cnt[N];
vector<pii>big_n[N];
int n,m;
int du[N];
void _insert(int u,int sum){if(sum>du[u]) sum=du[u]+1;//答案不會超過他的度數cnt[u][sum]++;if(cnt[u][sum]==1) tag[u][sum/block_size]++;
}
void _del(int u,int sum){if(sum>du[u]) sum=du[u]+1;cnt[u][sum]--;if(cnt[u][sum]==0) tag[u][sum/block_size]--;
}
void build(){for(int i=1;i<=n;i++){cnt[i].resize(du[i]+2);//每個點塊內的大小tag[i].resize(du[i]/block_size+2);//每個點快的數量for(int v:g[i]){if(du[v]>block_size){big_n[i].push_back({v,a[v]});//記錄大點鄰居}_insert(i,a[v]);}}
}
int q1(int u){for(int i=0;i<=du[u]/block_size;i++){//分塊查詢int k=tag[u][i];if(k==block_size) continue;for(int j=i*block_size;j<i*block_size+block_size;j++){if(!cnt[u][j]) return j;}}
}
void sovle(){scanf("%d%d",&n,&m);block_size=sqrt(n);for(int i=1;i<=n;i++) scd(a[i]);for(int i=1;i<=m;i++){int u,v;scdd(u,v);g[u].push_back(v);g[v].push_back(u);du[u]++;du[v]++;}build();int q;scd(q);//cout<<1<<endl;while(q--){int x, u;scanf("%d%d",&x,&u);if(x==1){int k;scanf("%d",&k);if(du[u]<=block_size){//小點直接修改for(int v:g[u]){_del(v,a[u]);_insert(v,k);}}a[u]=k;}else {for(pii &v:big_n[u]){//先查詢大點鄰居的值是否改變。if(a[v.fi]!=v.se){_del(u,v.se);_insert(u,a[v.fi]);v.se=a[v.fi];}}printf("%d\n",q1(u));}}for(int i=1;i<=n;i++) g[i].clear(),big_n[i].clear(),tag[i].clear(),cnt[i].clear(),du[i]=0;
}
int main()
{
#ifdef LOCALfreopen("in.txt", "r", stdin);
#else//iosint t=1;cin>>t;while(t--) sovle();
#endif // LOCALreturn 0;
}
總結
以上是生活随笔為你收集整理的HDU - 6756 Finding a MEX-分块思想的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。