【题解】「BZOJ4504」K个串

考虑二分答案 233

如果子树 max ⁡ \max max 都不能作为答案的话,就直接返回。

每找到一个叶节点就统计一次次数。

空间复杂度 O ( n log n ) O(n\text{log}n) O(nlogn)

时间复杂度 O ( ( n + k log n ) log N ) O((n+k\text{log}n)\text{log}N) O((n+klogn)logN)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
inline int read() {
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		x=(x<<1)+(x<<3)+c-'0';
		c=getchar();
	}
	return x*f;
}
int n,K,rt[N],tot;
map<int,int> c;
struct node {
	ll lc,rc,tag,max;
}t[N<<6];
void pushup(int o) {
	t[o].max=max(t[t[o].lc].max,t[t[o].rc].max)+t[o].tag;
}
int upd(int o,int l,int r,int ql,int qr,int x) {
	int oo=++tot;
	t[oo]=t[o];
	int mid=(l+r)/2;
	if(ql<=l&&r<=qr) {
		t[oo].tag+=x;
		t[oo].max+=x;
		return oo;
	}
	if(ql<=mid) t[oo].lc=upd(t[oo].lc,l,mid,ql,qr,x);
	if(mid<qr) t[oo].rc=upd(t[oo].rc,mid+1,r,ql,qr,x);
	pushup(oo);
	return oo;
}
void qry(int o,int l,int r,int ql,int qr,ll sol,int &ans) {
	if(!ans) return;
	if(t[o].max<sol) {
		return;
	}
	sol-=t[o].tag;
	if(l==r) {
		ans--;
		return;
	}
	int mid=(l+r)/2;
	if(ql<=mid) qry(t[o].lc,l,mid,ql,qr,sol,ans);
	if(mid<qr) qry(t[o].rc,mid+1,r,ql,qr,sol,ans);
}
bool check(ll mid) {
	int rest=K;
	for(int i=n;i>=1;i--) {
		qry(rt[i],1,n,1,i,mid,rest);
		if(!rest) return 1;
	}
	return 0;
}
signed main() {
//	freopen("data.in","r",stdin);
    n=read(),K=read();
	for(int i=1;i<=n;i++) {
		int x=read();
		rt[i]=upd(rt[i-1],1,n,c[x]+1,i,x);
		c[x]=i;
	}
	ll l=-1e18,r=1e18,res=0;
	while(l<=r) {
		ll mid=(l+r)/2;
		if(check(mid)) {
			res=mid,l=mid+1;
		}
		else {
			r=mid-1;
		}
	}
	printf("%lld",res);
}
posted @ 2022-02-24 16:25  仰望星空的蚂蚁  阅读(12)  评论(0)    收藏  举报  来源