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;
}
没了。。。