hdu6756 Finding a MEX(分块)

题目链接
把度数大于等于 n \sqrt n n 的点归为超级点
对每个超级点x维护一个长度为d_x的数组,每个位置y,当前仅当跟x相连的z中有a_z=y时,y=1,否则为0。
修改的时候只修改跟当前点连接的超级点的信息。
有两种写法,经验证,带log和不带log的时间 都差不多。。。

查询的时候,对不是超级点的询问直接暴力跑,带log的话就是,是超级点的就在bit上二分找答案,不带log的话就是对每个超级点也分块维护每个块的sum,查询的时候遍历块找答案。
1.纯分块写法:

#include 
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb emplace_back
#define mp make_pair
#define wzh(x) cerr<<#x<<' '<
int t,n,m,a[N],vis[N],num[N],d[N],bl[N],ans[N];
vector<int>v[N],mi[N],fk[N],gc[N];
struct FastIO  
{  
	static const int S=200;  
	int wpos;  
	char wbuf[S];  
	FastIO():wpos(0){}  
	inline int xchar()  
	{  
		static char buf[S];  
		static int len=0,pos=0;  
		if(pos==len) pos=0,len=fread(buf,1,S,stdin);  
		if(pos==len) exit(0);  
		return buf[pos++];  
	}  
	inline int read()  
	{  
		int s=1,c=xchar(),x=0;  
		while(c<=32) c=xchar();  
		if(c=='-') s=-1,c=xchar();  
		for(;'0'<=c&&c<='9';c=xchar()) x=x*10+c-'0';  
		return x*s;  
	}  
	~FastIO()  
	{  
		if(wpos) fwrite(wbuf,1,wpos,stdout),wpos=0;  
	}  
}io;

int main() {
	auto rd =[&](){
		return io.read();
	};
	for(t=rd();t;t--){
		n=rd();m=rd();
		int lar=0;
		for(int i=1;i<=n;i++){
			v[i].clear();
			mi[i].clear();
			d[i]=0;
		}
		for(int i=1;i<=n;i++)a[i]=rd();
		for(int i=1;i<=m;i++){
			int s,t;
			s=rd();t=rd();
			v[s].pb(t);
			v[t].pb(s);
			d[s]++;
			d[t]++;
		}
		auto ge =[&](int x,int y){
			int ans=(x+bl[y]-1)/bl[y];
			return ans;
		};
		int lim=sqrt(n)+1;
		for(int i=1;i<=n;i++){
			if(d[i]>lim){
				num[i]=++lar;
				bl[lar]=sqrt(d[i]);
				int now=(d[i]+bl[lar]-1)/bl[lar];
				fk[lar].resize(now+1);
				gc[lar].resize(d[i]+1);
				for(int j=0;j<=d[i];j++)gc[lar][j]=0;
				for(int j=0;j<=now;j++)fk[lar][j]=0;
				for(auto k:v[i]){
					if(d[k]>lim){
						mi[i].pb(k);
					}
					if(a[k]<=d[i]){
						if(++gc[lar][a[k]]==1){
							fk[lar][ge(a[k],lar)]++;
						}
					}
				}
			}else{
				for(auto k:v[i]){
					if(d[k]>lim){
						mi[i].pb(k);
					}
				}                   
			}
		}
		int Q;
		for(Q=rd();Q;Q--){
			int ty,u,x;
			ty=rd();
			if(ty==1){
				u=rd();x=rd();
				for(auto k:mi[u]){
					if(a[u]<=d[k]){
						if(--gc[num[k]][a[u]]==0){
							fk[num[k]][ge(a[u],num[k])]--;
						}
					}
					if(x<=d[k]){
						if(++gc[num[k]][x]==1){
							fk[num[k]][ge(x,num[k])]++;
						}
					}
				}
				a[u]=x;
			}else{
				u=rd();
				if(d[u]<=lim){
					for(int i=0;i<=d[u];i++)ans[i]=0;
					for(auto k:v[u])ans[a[k]]=1;
					for(int i=0;i<=d[u];i++){
						if(!ans[i]){
							printf("%d\n",i);
							break;
						}
					}
				}else{
					if(!gc[num[u]][0]){
						puts("0");
						continue;
					}
					int sum=bl[num[u]];
					int tmp=(d[u]+sum-1)/sum;
					for(int i=1;i<=tmp;i++){
						int res=min(d[u],i*sum)-(i-1)*sum;
						if(fk[num[u]][i]<res){
							for(int j=(i-1)*sum+1;j<=min(d[u],i*sum);j++){
								if(!gc[num[u]][j]){
									printf("%d\n",j);
									break;
								}
							}
							break;
						}
					}
				}
			}
		}
	}
	return 0;
}

2.bit写法:

#include 
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb emplace_back
#define mp make_pair
#define wzh(x) cerr<<#x<<' '<
int t, n, m, a[N], d[N], pre[N];
vector<int>v[N], me[N];
vector<int>mi[N];
set<int>s[N];
int vis[N];
multiset<int>q[N];
struct FastIO {
    static const int S = 200;
    int wpos;
    char wbuf[S];
    FastIO(): wpos(0) {}
    inline int xchar(){
        static char buf[S];
        static int len = 0, pos = 0;
        if (pos == len) pos = 0, len = fread(buf, 1, S, stdin);
        if (pos == len) exit(0);
        return buf[pos++];
    }
    inline int read() {
        int s = 1, c = xchar(), x = 0;
        while (c <= 32) c = xchar();
        if (c == '-') s = -1, c = xchar();
        for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
        return x * s;
    }
    ~FastIO()
    {
        if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
    }
} io;
vector<int>fk[444], gc[444];
int szz[N];
void add(int x, int y, int z) {
    int sz = szz[x];
    for (; y <= sz; y += y & -y)gc[x][y] += z;
}
int get(int x, int y) {
    int sz = 0;
    for (; y; y -= y & -y)sz += gc[x][y];
    return sz;
}
int num[N];
int main() {
    t = io.read();
    for (; t; t--) {
        n = io.read(); m = io.read();
        int lar = 0;
        for (int i = 1; i <= n; i++) {
            v[i].clear();
            a[i] = io.read();
            d[i] = 0;
            mi[i].clear();
        }
        for (int i = 1; i <= m; i++) {
            int s, t;
            s = io.read(); t = io.read();
            v[s].pb(t);
            v[t].pb(s);
            d[s]++; d[t]++;
        }
        int lim = sqrt(n) ;
        for (int i = 1; i <= n; i++) {
            if (d[i] >= lim) {
                num[i] = ++lar;
                szz[lar]=d[i];
                fk[lar].resize(d[i] + 2);
                gc[lar].resize(d[i] + 2);
                for (int j = 0; j <= d[i]; j++)fk[lar][j] = gc[lar][j] = 0;
                for (auto k : v[i]) {
                    if (a[k] <= d[i]) {
                        fk[lar][a[k]]++;
                        if (a[k]) {
                            if(fk[lar][a[k]]==1)add(lar, a[k], 1);
                        }
                    }
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            for (auto k : v[i]) {
                if (d[k] >= lim) {
                    mi[i].pb(k);
                }
            }
        }
        int Q;
        Q = io.read();
        for (; Q; Q--) {
            int ty, u, x;
            ty = io.read();
            if (ty == 1) {
                u = io.read();
                x = io.read();
                if (a[u] == x)continue;
                for (auto pac : mi[u]) {
                    int nu = num[pac];
                    if (a[u] <= d[pac]) {
                        fk[nu][a[u]]--;
                        if (fk[nu][a[u]] == 0 && a[u]) {
                            add(nu, a[u], -1);
                        }
                    }
                    if (x <= d[pac]) {
                        fk[nu][x]++;
                        if (fk[nu][x] == 1 && x) {
                            add(nu, x, 1);
                        }
                    }
                }
                a[u] = x;
            } else {
                u = io.read();
                if (d[u] >= lim) {
                    int nu = num[u];
                    if (!fk[nu][0])puts("0");
                    else {
                        int l = 1, r = d[u], ans = -1;
                        while (l <= r) {
                            int mid = l + r >> 1;
                            if (get(nu, mid) < mid)ans = mid, r = mid - 1;
                            else l = mid + 1;
                        }
                        assert(ans != -1);
                        printf("%d\n", ans);
                    }
                }
                else {
                    for (int i = 0; i <= d[u]; i++)vis[i] = 0;
                    for (auto k : v[u]) {
                        if (a[k] <= d[u])vis[a[k]] = 1;
                    }
                    for (int i = 0; i <= d[u]; i++) {
                        if (!vis[i]) {
                            printf("%d\n", i);
                            break;
                        }
                    }
                }
            }
        }
        for (int i = 1; i <= lar; i++)gc[i].clear(), fk[i].clear();
    }
    return 0;
}

你可能感兴趣的:(分块)