2018.9.16 练习赛 数据结构专练

T1 修剪草坪

题解:

类似烽火传递,设定状态:\(f[i]\)为讨论到第i号点的最小损失,则转移方程为:\(f[i]=min{f[j]}+a[i] (i-k-1<=j<=i-1)\),时间复杂度:\(O(nk)\)可使用单调队列维护最小值,本次使用\(zkw\)维护区间最小

\(code\):

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<ctype.h>
#include<vector>
#define ll long long
#define inf 2312312321321312LL
#define l(x) x<<1
#define r(x) x<<1|1
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc() {
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
void read(T &x) {
	char tt;
	bool flag=0;
	while(!isdigit(tt=gc())&&tt!='-');
	tt=='-'?(x=0,flag=1):(x=tt-'0');
	while(isdigit(tt=gc())) x=x*10+tt-'0';
	if(flag) x=-x;
}

ll n,k,sum,ans=inf,M=1;
ll a[100005],f[100005],c[100005*40];
void modify(ll x,ll d) {
	x+=M;
	c[x]=min(c[x],d);
	while(x>1) {
		x>>=1;
		c[x]=min(c[l(x)],c[r(x)]);
	}
}

ll query(ll x,ll y) {
	ll minn=inf;
	for(x+=M-1,y+=M+1; x^y^1; x>>=1,y>>=1) {
		if(~x&1) minn=min(minn,c[x^1]);
		if(y&1) minn=min(minn,c[y^1]);
	}
	return minn;
}

int main() {
	freopen("grass.in","r",stdin);
	freopen("grass.out","w",stdout);
	read(n),read(k);
	while(M<=n+1) M<<=1;
	for(int i=2; i<=n+1; i++) read(a[i]),sum+=a[i],f[i]=inf;
	memset(c,127,sizeof(c));
	f[1]=0;
	modify(1,0);
	for(int i=2; i<=n+1; i++) {
		ll minn=query(max(i-k-1,1LL),i-1);
		f[i]=min(f[i],minn+a[i]);
		modify(i,f[i]);
	}
	printf("%lld",sum-query(n-k+1,n+1));
}

T2 修整花园

题解:

用大根堆维护\(in\),\(out\),分别表示需买入和需送出,存储:\(i*z+v_j\),保证每次可以对前面的选择“后悔”

\(code:\)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<ctype.h>
#include<vector>
#define ll long long
#define inf 2312312321321312LL
#define l(x) x<<1
#define r(x) x<<1|1
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc() {
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
void read(T &x) {
	char tt;
	bool flag=0;
	while(!isdigit(tt=gc())&&tt!='-');
	tt=='-'?(x=0,flag=1):(x=tt-'0');
	while(isdigit(tt=gc())) x=x*10+tt-'0';
	if(flag) x=-x;
}

priority_queue<ll>in_,out_;
ll v,n,x,y,z,ans;
int main() {
	read(n),read(x),read(y),read(z);
	for(int i=1; i<=n; i++) {
		ll a,b;
		read(a),read(b);
		if(a-b>0) {
			for(int k=1; k<=a-b; k++) {
				if(in_.empty())
					ans+=y,out_.push(i*z+y);
				else {
					v=-in_.top();
					if(i*z+v<y)
						ans+=i*z+v,in_.pop(),out_.push(i*z*2+v);
					else
						ans+=y,out_.push(i*z+y);
				}
			}
		} else {
			for(int k=1; k<=b-a; k++) {
				if(out_.empty())
					ans+=x,in_.push(i*z+x);
				else {
					v=-out_.top();
					if(i*z+v<x)
						ans+=i*z+v,out_.pop(),in_.push(i*z*2+v);
					else
						ans+=x,in_.push(i*z+x);
				}
			}
		}
	}
	printf("%lld",ans);
}

T3 人数统计

题解:

\(dfs\)序后分块维护块内有序,查询时二分查找块内,块两端暴力查找即可

\(code:\)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<math.h>
#include<ctype.h>
#include<vector>
#define ll long long
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc() {
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
void read(T &x) {
	char tt;
	bool flag=0;
	while(!isdigit(tt=gc())&&tt!='-');
	tt=='-'?(x=0,flag=1):(x=tt-'0');
	while(isdigit(tt=gc())) x=x*10+tt-'0';
	if(flag) x=-x;
}

ll n,tmp[100005],a[100005],s,block[320][320];
vector<ll>G[100005];
ll fa[100005],pos[100005][2],tot;

void dfs(ll x,ll pre) {
	fa[x]=pre;
	pos[x][0]=++tot;
	int siz=G[x].size();

	for(int i=0; i<siz; i++) {
		ll p=G[x][i];
		if(p==pre) continue;
		dfs(p,x);
	}
	pos[x][1]=tot;
}

ll query(ll x,ll y,ll d) {
	ll lid=(x-1)/s+1;
	ll rid=(y-1)/s+1;
	ll tot=0;
	if(lid==rid) {
		for(int i=x; i<=y; i++)
			if(a[i]>d) tot++;
	} else {
		for(int i=x; i<=lid*s; i++)
			if(a[i]>d) tot++;
		for(int i=(rid-1)*s+1; i<=y; i++)
			if(a[i]>d) tot++;
		for(int i=lid+1; i<rid; i++) {
			int id=upper_bound(block[i]+1,block[i]+1+s,d)-block[i];
			tot+=s-id+1;
		}
	}
	return tot;
}

int main() {
	read(n);
	for(int i=1; i<=n; i++)
		read(tmp[i]);
	for(int i=2; i<=n; i++) {
		ll x;
		read(x);
		G[x].push_back(i);
	}
	dfs(1,1);
	for(int i=1; i<=n; i++) a[pos[i][0]]=tmp[i];
	s=sqrt(n);
	for(int i=1; i<=n; i++)
		block[(i-1)/s+1][(i-1)%s+1]=a[i];
	for(int i=1; i<=s+1; i++) sort(block[i]+1,block[i]+1+s);
	for(int i=1; i<=n; i++)
		printf("%lld\n",query(pos[i][0],pos[i][1],a[pos[i][0]]));
}

posted @ 2018-09-16 16:18  Katoumegumi  阅读(76)  评论(0编辑  收藏  举报
返回顶部