[图论][STL][分层图] 小技巧练习

T1 Ostring

题意

给出字符串,要求实现操作:

  1. 翻转
  2. 在队首或队尾插入字符

正解

双端队列deque<char>q
记录反转奇偶性rev^=1

T2 不同字符个数

题意

给出字符串,要求实现操作:

  1. 更改
  2. 询问区间不同字母个数

正解

  1. 线段树
  2. 树状数组,加一维tre[26][N]
  3. set内部有序(红黑树)
    set支持删除操作,lower_bound
    查询第一个>=l的数的位置,如果<=r则有这种字符

T3 Subway

题意

一个图,每条边有颜色
求最小1到n经过不同颜色的种数
颜色种数 c o l col col很大

题解

(1) 分层图最短路
无贡献的边为一层,层之间有贡献
c o l col col层,但是只有 n n n个点

(2)魔改Dijkstra
又用set,记录每个点已用的颜色
扩展时对于一条边 u → v u\to v uv,颜色在 u u uset中用过,无贡献;反之有贡献;最后将这条边的颜色加入 v v v

T4 两种货币

题意


初始 s s s个币,每条边花费 a e a_e ae币,耗时 b e b_e be
在每个点可以取任意次币,每次取 c e c_e ce币,耗时 d e d_e de
求从源点到所有点的最少耗时

正解

分层图最短路

金币数为层数,有转移:
dis[v][w-a[e]]>dis[u][w]+b[e],走一条边,注意要判w>=a[e]
dis[u][min(w+c[u],2500)]>dis[u][w]+d[u],取钱

#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
	int i=0,f=1;char ch=0;
	while(!isdigit(ch)&&ch!='-') ch=getchar();
	if(ch=='-') ch=getchar(),f=-1;
	while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
	return i*f;
}

const int N=2505,INF=2147483647;
int n,m,s;
int tot,first[N],nxt[N<<1],aim[N<<1];
int dis[105][N],a[N<<1],b[N<<1],c[N],d[N];

struct traid{
	int first,second,third;
	traid(){}
	traid(int _T1,int _T2,int _T3){
		first=_T1,second=_T2,third=_T3;
	}
	friend inline bool operator < (traid x,traid y){
		return x.first<y.first;
	}
};

priority_queue<traid>q;

void ljb(int u,int v,int x,int y){
	++tot;
	nxt[tot]=first[u];
	first[u]=tot;
	aim[tot]=v;
	a[tot]=x;
	b[tot]=y;
	return;
}

void Dijkstra(){
	for(int i=1;i<=n;++i)
		for(int j=0;j<=N;++j)
			dis[i][j]=INF;
	dis[1][s]=0;
	q.push(traid(0,1,s));
	while(!q.empty()){
		int u=q.top().second,w=q.top().third;q.pop();
		for(int e=first[u];e;e=nxt[e]){
			int v=aim[e];
			if(w>=a[e]&&dis[v][w-a[e]]>dis[u][w]+b[e]){
				dis[v][w-a[e]]=dis[u][w]+b[e];
				q.push(traid(-dis[v][w-a[e]],v,w-a[e]));
			}
		}
		if(dis[u][min(w+c[u],2500)]>dis[u][w]+d[u]){
			dis[u][min(w+c[u],2500)]=dis[u][w]+d[u];
			q.push(traid(-dis[u][min(w+c[u],2500)],u,min(w+c[u],2500)));
		}
	}
}

int main(){
	
	freopen("coin.in","r",stdin);
	freopen("my.out","w",stdout);
	
	n=in,m=in,s=in;
	s=min(s,2500);
	for(int i=1;i<=m;++i){
		int u=in,v=in,x=in,y=in;
		ljb(u,v,x,y);
		ljb(v,u,x,y);
	}
	for(int i=1;i<=n;++i) c[i]=in,d[i]=in;
	Dijkstra();
	for(int i=2;i<=n;++i){
		int ans=INF;
		for(int j=0;j<=2500;++j)
			ans=min(ans,dis[i][j]);
		printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值