2019.07.11【NOIP提高组】模拟 A 组

JZOJ 3326 矮人排队

题目

交换两个位置上的数,或者查询权值区间 [ l ∼ r ] [l\sim r] [lr]是否连续


分析

用权值线段树,维护区间最大值和区间最小值的位置,判断是否连续


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define swap(a,b) (a^=b,b^=a,a^=b)
using namespace std;
const int N=201001;
int w1[530001],w2[530001],pos[N],n,bas,m;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void pdown(int k){w1[k]=min(w1[k<<1],w1[k<<1|1]),w2[k]=max(w2[k<<1],w2[k<<1|1]);}
inline void update(int x,int y){
	w1[x+bas]=w2[x+bas]=y;
	for (x+=bas,x>>=1;x;x>>=1) pdown(x);
}
inline void query(int x,int y){
	rr int ans1=w1[0],ans2=0,t1=x,t2=y;
	for (x+=bas-1,y+=bas+1;x^y^1;x>>=1,y>>=1){
		if (!(x&1)) ans1=min(ans1,w1[x^1]),ans2=max(ans2,w2[x^1]);
		if (y&1) ans1=min(ans1,w1[y^1]),ans2=max(ans2,w2[y^1]);
	}
	ans2+t1==t2+ans1?printf("YES\n"):printf("NO\n");
}
signed main(){
	n=iut(); m=iut(); for (bas=1;(bas<<=1)<n+3;); memset(w1,42,sizeof(w1));
	for (rr int i=1,x;i<=n;++i) x=iut(),w1[bas+x]=w2[bas+x]=i,pos[i]=x;
	for (rr int i=bas-1;i;--i) pdown(i);
	for (rr int i=1;i<=m;++i){
		rr int q=iut(),x=iut(),y=iut();
		if (!(q&1)) query(x,y);
		    else update(pos[x],y),update(pos[y],x),swap(pos[x],pos[y]);
	}
	return 0;
}

JZOJ 3237 间谍派遣(怀疑是和B组第二题对调了,因为这道题秒切)


BZOJ 3482 hiperprostor JZOJ 3238 超空间旅行

题目

给出一个有向图,一些边权是变量x,多组询问两点间可能路径个数和可能路径的总和


分析

那么可能路径能表示出 y = k x + b y=kx+b y=kx+b的形式,那么跑最短路求出k和b,再维护上凸壳,每一段用等差数列算出答案,bzoj貌似卡spfa,于是我就打了dijkstra,结果jzojTLE了,所以我就吸了好多口氧,如果我码完SPFA再说吧


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>
#define rr register
using namespace std;
const int inf=707406378; double b[501];
struct node{int y,w,next;}e[10011]; bool v[501][501];
int n,m,ls[501],dis[501][501],a[501],s,t,cnt;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
struct rec{
    int x,y,dist;
    bool operator <(const rec &t)const{
	    return dist!=t.dist?dist<t.dist:y<t.y;
	}
}heap[500011];
inline void Push(rec d){
    heap[++cnt]=d;
    rr int x=cnt;
    while (x>1){
        if (heap[x]<heap[x>>1])
            swap(heap[x>>1],heap[x]),x>>=1;
        else return;
    }
}
inline void Pop(){
    heap[1]=heap[cnt--];
    rr int x=1;
    while ((x<<1)<=cnt){
        rr int y=x<<1;
        if (y<cnt&&heap[y+1]<heap[y]) ++y;
        if (heap[y]<heap[x]) swap(heap[y],heap[x]),x=y;
        else return;
    }
}
inline void spfa(){
	memset(dis,42,sizeof(dis)),memset(v,0,sizeof(v));
	heap[cnt=1]=(rec){s,0,0},dis[s][0]=0,v[s][0]=1;
	while (cnt){
		rr rec p=heap[1]; Pop(); v[p.x][p.y]=1;
		if (dis[p.x][p.y]!=p.dist) continue;
		for (rr int i=ls[p.x];i;i=e[i].next)
		if (p.y+(!e[i].w)<=n&&dis[e[i].y][p.y+(!e[i].w)]>dis[p.x][p.y]+e[i].w){
		    rr int zx=e[i].y,zy=p.y+(!e[i].w);
			dis[zx][zy]=dis[p.x][p.y]+e[i].w;
			if (!v[zx][zy]) Push((rec){zx,zy,dis[zx][zy]});
		}
	}
}
inline long long add(int k,int b,int l,int r){return (1ll*k*(l+r)+b*2)*(r-l+1)>>1;}
inline double slope(int x,int y){return 1.0*(dis[t][y]-dis[t][x])/(x-y);}
inline void answ(){
	spfa(); rr int flag=0;
	for (rr int ttt=0;ttt<=n;++ttt) if (dis[t][ttt]!=inf) {flag=1; break;}
	if (!flag) {printf("0 0\n"); return;}
	if (dis[t][0]==inf) {printf("inf\n"); return;}
	rr int top=0;
	for (rr int i=n;~i;--i){
		if (dis[t][i]==inf) continue;
		while (top&&b[top]>=slope(a[top],i)) --top;
		if (top) b[top+1]=slope(a[top],i); a[++top]=i;
	}
	rr int sum=b[top]; rr long long ans=0;
	for (rr int i=1;i<top;++i) ans+=add(a[i],dis[t][a[i]],(int)b[i]+1,(int)b[i+1]);
	if (sum*a[top-1]+dis[t][a[top-1]]!=dis[t][0]||top==1) ans+=dis[t][0],++sum;
	printf("%d %lld\n",sum,ans);
}
signed main(){
    n=iut(); m=iut();
    for (rr int i=1;i<=m;++i){
    	rr int x=iut(),y=iut(),w=0; rr char c=getchar();
    	if (c!='x')	while (isdigit(c)) w=(w<<3)+(w<<1)+(c^48),c=getchar();
		e[i]=(node){y,w,ls[x]},ls[x]=i;
	}
	for (rr int q=iut();q;--q) s=iut(),t=iut(),answ();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值