3.5提高A组

0:4763,旷野大计算
dalao题解
捋捋思路
按块处理,因为删数麻烦,所以尽量不删,因而用只增莫队
处理一个块时,l为块末与询问r的最小值,然后从后向前进入
先将r移到下一个块的第一;
保证能取到答案,la和bj:p2记录了在更新当前答案时,下一个块的答案,
从l到(块末或询问区间末)清楚标记,使得当前取值不影响到下一个块的更新

//3y5h旷野大计算3y5h 
//莫队 (只增莫队 Al
//https://blog.csdn.net/hiweibolu/article/details/52475866
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int p1,n,m,tot;
int op[maxn]; 
ll ans[maxn],q[maxn],js[maxn],bj[maxn],la[maxn];
ll p2,an;
struct node{
	int l,r,id,w,res;
}a[maxn<<2],w[maxn];
inline int read(){
	int x=0,w=0;char ch=0;
	while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return w?-x:x;
}
bool cmp1(node x,node y){return x.w<y.w;}
bool cmp2(node x,node y){
	if(op[x.l]==op[y.l]) return x.r<y.r;//op?
	else return op[x.l]<op[y.l];
}
bool cmp3(node x,node y){return x.id<y.id;}
int main(){
//	freopen("mode0.in","r",stdin);
//	freopen("ans.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++) //离散化 
		w[i].w=read(),w[i].id=i;
	sort(w+1,w+n+1,cmp1);
	for(int i=1;i<=n;i++) 
		w[i].res=w[i].w>w[i-1].w?++tot:tot;
	sort(w+1,w+n+1,cmp3);
	
	int pq=sqrt(n)+1;
	//莫队分块!
	for(int i=1;i<=n;i++) op[i]=i/pq+1; 
	
	for(int i=1;i<=m;i++)
		a[i].l=read(),a[i].r=read(),a[i].id=i;
	sort(a+1,a+m+1,cmp2);
	int l=0,r=0;
	for(int i=1;i<=m;i++){
		if(op[a[i].l]!=op[a[i-1].l]){
			memset(la,0,sizeof(la));
			p1=op[a[i].l]*pq;
			r=p1+1;
			p2=an=0;
		}
		l=min(a[i].r+1,p1+1);
		while(l>a[i].l) 
			l--,an=max(an,(++bj[w[l].res]+la[w[l].res])*w[l].w);			
		while(r<=a[i].r){
			p2=max(p2,(ll)(++la[w[r].res])*w[r].w);
			an=max(an,(ll)(bj[w[r].res]+la[w[r].res])*w[r].w);
			r++;
		} 
		for(int j=l;j<=a[i].r&&j<=p1;j++) bj[w[j].res]--;
		ans[a[i].id]=an;an=p2;
	}
	for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
	return 0;
} 

然而考场上又没想到莫队,打了未分块的(

1:4771 爬山
考场未判环暴力spfa30

//爬山3y5h30分暴力spfa 
#include<bits/stdc++.h>
#include<queue>
using namespace std;
const int maxn=5e5+10;
int n,m,s,ans,num,tot,T,w[maxn],head[maxn],d[maxn],tt[maxn];
bool v[maxn],t[maxn];
struct node{
	int nxt,v;
}a[maxn<<1];
inline int read(){
	int x=0,w=0;char ch=0;
	while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return w?-x:x;
}
inline void add(int u,int v){
	a[++tot].nxt=head[u],a[tot].v=v;head[u]=tot;
}
void maxlong(){
	queue<int>q;
	q.push(s);v[s]=1;d[s]=w[s];
	while(q.size()){
		int x=q.front();q.pop();v[x]=0;
		for(int i=head[x],y;i;i=a[i].nxt){
			y=a[i].v;
			if(d[y]<d[x]+w[y]){
				d[y]=d[x]+w[y];
				if(!v[y]){
					v[y]=1;q.push(y);
				}
			}
		}
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u,v;
		u=read(),v=read();
		add(u,v); 
	}
	for(int i=1;i<=n;i++) w[i]=read();
	s=read(),T=read();
	for(int i=1;i<=T;i++){
		int x=read();t[x]=1;tt[++num]=x;
	}
	maxlong();
	for(int i=1;i<=num;i++)
		ans=max(ans,d[tt[i]]);
	printf("%d",ans);
	return 0;	
} 

人工栈真的难受
满分

//爬山3y5h
//tarjan(人工栈)缩点+ spfa
//tarjan掌握的还不熟练 
//人工栈暴露缺陷 
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5e5+10;
int n,m,tot,dep,head[maxn],link[maxn],sd[maxn];
int dfn[maxn],low[maxn],stac[maxn],sta[maxn];
int s,T,t[maxn];
ll ans,d[maxn],w[maxn];
bool v[maxn];
struct node{
	int u,v,nxt;
}a[maxn],b[maxn];
inline int read(){
	int x=0,w=0;char ch=0;
	while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return w?-x:x;
}
inline void Add(int u,int v){
	b[++tot].nxt=link[u],b[tot].v=v,link[u]=tot;
}
inline void add(int u,int v,int i){
	a[i].u=u,a[i].nxt=head[u],a[i].v=v,head[u]=i;
}
void tarjan(int u){
	int tops,top,num;
	tops=top=num=0;
	bool flag;
	stac[++tops]=u;
	while(tops){
		flag=0;
		int x=stac[tops];
		if(!dfn[x]){
			dfn[x]=low[x]=num++;
			sta[++top]=x;//
			v[x]=1;
		}		
		for(int i=head[x],y;i;i=a[i].nxt){
			y=a[i].v;
			if(!dfn[y]){
				stac[++tops]=y;
				flag=1;
				break;
			}
			else if(v[y]) low[x]=min(low[x],dfn[y]);//!v[y]
		}
		if(flag) continue;
		if(low[x]==dfn[x]){
			int y;//cout<<"yunxing"<<endl;
			while(sta[top]!=x){
				y=sta[top];
				sd[y]=x; 
			//	cout<<y<<" "<<sd[y]<<" "<<x<<endl;
				v[y]=0;
				w[x]+=w[y];
				top--;
			}
			v[x]=0;
			top--; //忽略了对x的处理 
		}
		low[stac[--tops]]=min(low[stac[tops]],low[x]);
	} 
}
void lb(){
	for(int i=1;i<=m;i++){
		int x=a[i].u,y=a[i].v;
	//	printf("%d %d %d %d\n",x,y,sd[x],sd[y]); 
		if(sd[x]!=sd[y])//2加新边 
		Add(sd[x],sd[y]);//cout<<x<<" "<<y<<endl;
	}
} 
void spfa(){
	memset(v,0,sizeof(v));
	queue<int>q;
	q.push(sd[s]);v[sd[s]]=1;d[sd[s]]=w[sd[s]];
	while(q.size()){
		int x=q.front();q.pop();v[x]=0;
		for(int i=link[x],y;i;i=b[i].nxt){
			y=b[i].v;
			if(d[y]<d[x]+w[y]){
				d[y]=d[x]+w[y];
				if(!v[y]){
					v[y]=1;q.push(y);
				}
			}
		}
	}
}
int main(){
//	freopen("climb9.in","r",stdin); 
	n=read(),m=read();
	int x,y;
	for(int i=1;i<=m;i++){
		x=read(),y=read();
		add(x,y,i);
	}
	for(int i=1;i<=n;i++) sd[i]=i,w[i]=read();
	s=read(),T=read();
	for(int i=1;i<=T;i++)
	t[i]=read();
	for(int i=1;i<=n;i++)
		if(!dfn[i]) tarjan(i);
	lb();		
	spfa();
	for(int i=1;i<=T;i++)
	ans=max(ans,d[sd[t[i]]]);
	printf("%lld",ans);//1:输出再次忘ll 
	return 0;
} 

2:4772运输妹子
十分暴力

//运输妹子3y5h30分 
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10,N=5e3+10;
ll W,L,a[maxn];
int n,w[N][N],ans;
inline int read(){
	int x=0,w=0;char ch=0;
	while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return w?-x:x;
}
int main(){
	n=read();
	scanf("%lld%lld",&L,&W);
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			w[i][j]=abs(a[i]-a[j]);
		}
		sort(w[i]+1,w[i]+n+1);
		ll res=0;int o=0;
		for(int j=1;j<=n;j++){
			res+=w[i][j];o=j;
			if(res>W) break;
		}
		ans=max(ans,o-1);
	}
	printf("%d",ans);
	return 0;
} 

运输妹子3y5h 100分O(n)好想
相当于枚举区间,区间满足的条件为从中位数到左,右农田的费用<=总钱数
那就两个指针跳啊跳
满足r+,不满足l-

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+100,N=1e3+10;
ll W,L,sum[maxn],ans,a[maxn];
int n; 
inline int read(){
	int x=0,w=0;char ch=0;
	while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return w?-x:x;
}
int main(){
	n=read();
	scanf("%lld%lld",&L,&W);
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
	ll l=1,r=1,k;//O(n)愚蠢的忘给k开ll 
	for(int i=2;i<=n;i++){
		ll mid=(r+l)>>1;
		r++;
		k=sum[r]-sum[mid]+(mid*2-l-r)*a[mid]-sum[mid-1]+sum[l-1];
		if(k>W) l++;
		else ans=max(ans,r-l+1);
	}
	printf("%d",ans);
	return 0;
} 

没了。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值