T1 Ostring
题意
给出字符串,要求实现操作:
- 翻转
- 在队首或队尾插入字符
正解
双端队列deque<char>q
记录反转奇偶性rev^=1
T2 不同字符个数
题意
给出字符串,要求实现操作:
- 更改
- 询问区间不同字母个数
正解
- 线段树
- 树状数组,加一维
tre[26][N]
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
u→v,颜色在
u
u
u的set
中用过,无贡献;反之有贡献;最后将这条边的颜色加入
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;
}