1. 程式人生 > 其它 >題解 Dove 打撲克

題解 Dove 打撲克

傳送門

考場上覺得複雜度是假的就沒怎麼優化,然後考完題解幫我證明了它是真的……

首先合併可以用並查集維護,可以順便維護出集合的大小
對於操作2,發現如果 \(size_i\) 是確定的,可以用權值線段樹很方便的維護出合法的 \(size_j\)的個數
每次只需枚舉出現過的 \(size_i\) 即可,所以我覺得複雜度是假的

  • 如果存在 \(\sum a_i = n\) ,那麼有 \(diff \{a_i\} \leqslant \sqrt n\)

我們有 \(\sum size_i = n\) ,所以不同的size個數只有不超過根號個
所以用個unordered_set維護當前存在的size,線段樹查詢即可

yysy,我把線段樹換成樹狀陣列從1700ms變成了400ms

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long 
#define reg register int
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int fa[N], cnt[N];
bool vis[N];
inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}

namespace force{
	void solve() {
		for (int i=1; i<=n; ++i) fa[i]=i, cnt[i]=1, vis[i]=1;
		ll ans;
		for (int i=1,x,y,c,f1,f2; i<=m; ++i) {
			if (read()&1) {
				x=read(); y=read();
				f1=find(x), f2=find(y);
				if (f1!=f2) {
					cnt[f1]+=cnt[f2];
					vis[f2]=0;
					fa[f2]=f1;
				}
			}
			else {
				ans=0;
				c=read();
				for (int i=1; i<=n; ++i) if (vis[i]) 
					for (int j=i+1; j<=n; ++j) if (vis[j]) 
						if (abs(cnt[i]-cnt[j])>=c) ++ans;
				printf("%lld\n", ans);
			}
		}
		exit(0);
	}
}

namespace task1{
	int tl[N<<2], tr[N<<2], sum[N<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define sum(p) sum[p]
	#define pushup(p) sum(p)=sum(p<<1)+sum(p<<1|1)
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void upd(int p, int pos, int dat) {
		if (tl(p)==tr(p)) {sum(p)+=dat; return ;}
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) upd(p<<1, pos, dat);
		else upd(p<<1|1, pos, dat);
		pushup(p);
	}
	int query(int p, int l, int r) {
		if (l<=tl(p) && r>=tr(p)) return sum(p);
		int mid=(tl(p)+tr(p))>>1, ans=0;
		if (l<=mid) ans+=query(p<<1, l, r);
		if (r>mid) ans+=query(p<<1|1, l, r);
		return ans;
	}
	void solve() {
		build(1, 1, n); upd(1, 1, n);
		for (int i=1; i<=n; ++i) fa[i]=i, cnt[i]=1, vis[i]=1;
		ll ans;
		for (int i=1,x,y,c,f1,f2; i<=m; ++i) {
			if (read()&1) {
				x=read(); y=read();
				f1=find(x), f2=find(y);
				if (f1!=f2) {
					upd(1, cnt[f1], -1); upd(1, cnt[f2], -1);
					cnt[f1]+=cnt[f2];
					upd(1, cnt[f1], 1);
					vis[f2]=0;
					fa[f2]=f1;
				}
			}
			else {
				ans=0;
				c=read();
				for (reg i=1,l,r; i<=n; ++i) if (vis[i]) {
					if ((l=cnt[i]-c)>=1) ans+=query(1, 1, l)-(c==0);
					if ((r=cnt[i]+c+(c==0))<=n) ans+=query(1, r, n);
				}
				printf("%lld\n", ans/2);
			}
		}
		exit(0);
	}
}

namespace task2{
	int tl[N<<2], tr[N<<2], sum[N<<2], tot[N], maxn=1;
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define sum(p) sum[p]
	#define pushup(p) sum(p)=sum(p<<1)+sum(p<<1|1)
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void upd(int p, int pos, int dat) {
		if (tl(p)==tr(p)) {sum(p)+=dat; return ;}
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) upd(p<<1, pos, dat);
		else upd(p<<1|1, pos, dat);
		pushup(p);
	}
	int query(int p, int l, int r) {
		if (l<=tl(p) && r>=tr(p)) return sum(p);
		int mid=(tl(p)+tr(p))>>1, ans=0;
		if (l<=mid) ans+=query(p<<1, l, r);
		if (r>mid) ans+=query(p<<1|1, l, r);
		return ans;
	}
	void solve() {
		build(1, 1, n); upd(1, 1, n); tot[1]=n;
		for (int i=1; i<=n; ++i) fa[i]=i, cnt[i]=1, vis[i]=1;
		ll ans;
		for (int i=1,x,y,c,f1,f2; i<=m; ++i) {
			if (read()&1) {
				x=read(); y=read();
				f1=find(x), f2=find(y);
				if (f1!=f2) {
					upd(1, cnt[f1], -1); upd(1, cnt[f2], -1);
					--tot[cnt[f1]]; --tot[cnt[f2]];
					cnt[f1]+=cnt[f2];
					++tot[cnt[f1]]; maxn=max(maxn, cnt[f1]);
					upd(1, cnt[f1], 1);
					vis[f2]=0;
					fa[f2]=f1;
				}
			}
			else {
				ans=0;
				c=read();
				for (reg i=1,l,r; i<=maxn; ++i) if (tot[i]) {
					if ((l=i-c)>=1) ans+=1ll*tot[i]*(query(1, 1, l)-(c==0));
					//cout<<"l: "<<l<<' '<<tot[i]*(query(1, 1, l)-(c==0))<<endl;
					if ((r=i+c+(c==0))<=n) ans+=1ll*tot[i]*query(1, r, n);
					//cout<<"r: "<<r<<' '<<query(1, r, n)<<endl;
				}
				printf("%lld\n", ans/2);
			}
		}
		exit(0);
	}
}

namespace task{
	unordered_set<int> s;
	unordered_set<int>::iterator sta[N];
	int sum[N], tot[N], top;
	inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) sum[i]+=dat;}
	inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=sum[i]; return ans;}
	void solve() {
		upd(1, n); tot[1]=n; s.insert(1);
		for (int i=1; i<=n; ++i) fa[i]=i, cnt[i]=1, vis[i]=1;
		ll ans;
		for (int i=1,x,y,c,f1,f2; i<=m; ++i) {
			if (read()&1) {
				x=read(); y=read();
				f1=find(x), f2=find(y);
				if (cnt[f1]<cnt[f2]) swap(f1, f2);
				if (f1!=f2) {
					upd(cnt[f1], -1); upd(cnt[f2], -1);
					--tot[cnt[f1]]; --tot[cnt[f2]];
					cnt[f1]+=cnt[f2];
					if (++tot[cnt[f1]]==1) s.insert(cnt[f1]);
					upd(cnt[f1], 1);
					vis[f2]=0;
					fa[f2]=f1;
				}
			}
			else {
				ans=0;
				c=read();
				int l, r;
				for (unordered_set<int>::iterator it=s.begin(); it!=s.end(); ++it) {
					//cout<<"*it: "<<*it<<endl;
					if (!tot[*it]) {sta[++top]=it; continue;}
					if ((l=*it-c)>=1) ans+=1ll*tot[*it]*(query(l)-(c==0));
					//cout<<"l: "<<l<<' '<<tot[i]*(query(1, 1, l)-(c==0))<<endl;
					if ((r=*it+c+(c==0))<=n) ans+=1ll*tot[*it]*(query(n)-query(r-1));
					//cout<<"r: "<<r<<' '<<query(1, r, n)<<endl;
				}
				while (top) s.erase(sta[top--]);
				printf("%lld\n", ans/2);
			}
		}
		exit(0);
	}
}

signed main()
{
	n=read(); m=read();
	//if (n<=100) force::solve();
	//else if (n<=1000) task1::solve();
	//else task2::solve();
	task::solve();
	
	return 0;
}