过路费
原题 CodeForces gym 101630 J 。
经典的错算例子。
如果我们只支付 ≥ m i d \ge mid ≥mid边的费用,那么 < m i d <mid <mid的边边权是 0 0 0,可以随便经过。
因此我们枚举边权,把 w w w改为 max ( 0 , w − m i d ) \max(0,w-mid) max(0,w−mid),然后跑最短路,答案是 d i s [ n ] + k ∗ m i d dis[n]+k*mid dis[n]+k∗mid
如果经过的 ≥ m i d \ge mid ≥mid的边超过 k k k的话,那么算出来比答案大,原因在于对 > k >k >k条边支付了费用。
如果经过的 ≥ m i d \ge mid ≥mid的边不足 k k k的话,那么算出来还是比答案大
因此如果对答案有贡献,那么经过的 ≥ m i d \ge mid ≥mid的边一定恰好是 k k k条
如果本身经过的边就不足 k k k条,那么让 m i d = 0 mid=0 mid=0即可。
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define db double
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N=3005;
//自闭
int n,m,K,vis[N];
int head[N<<2],nxt[N<<2],to[N<<2],w[N<<2],tot;
ll dis[N],res(inf);
void add(int x,int y,int z){
to[++tot]=y,w[tot]=z,nxt[tot]=head[x],head[x]=tot;
}
priority_queue<pair<ll,int>>Q;
struct node{
int u,v,w;
}e[3005];
void dij(){
dis[1]=0,Q.push({0,1});
while(Q.size()){
int u=Q.top().se;Q.pop();if(vis[u])continue;vis[u]=1;
for(int k=head[u];k;k=nxt[k]){
int v=to[k],W=w[k];
if(dis[u]+W<dis[v])dis[v]=dis[u]+W,Q.push({-dis[v],v});
}
}
}
ll solve(int mid){
for(int i=1;i<=n;i++)head[i]=0,vis[i]=0,dis[i]=inf;tot=0;
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v,w=e[i].w;
add(u,v,max(0,w-mid)),add(v,u,max(0,w-mid));
}dij();return dis[n]+(ll)K*mid;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m>>K;
for(int i=1;i<=m;i++){
int u,v,w;cin>>u>>v>>w,e[i]={u,v,w};
}
res=solve(0);
for(int i=1;i<=m;i++){
res=min(res,solve(e[i].w));
}
cout<<res;
}
搞破坏
平面图中的欧拉定理:
设G为任意的联通平面图,则v-e+f=2,v是G的顶点数,e是G的边数,f是G的面数。
可以简单理解为,首先建一棵树,然后每新增一条边,就会多分割出一个平面。
对于每两块相邻的可用格子,连一条边,形成一个图G。题目就是问矩形区域内导出子图中连通块个数。
网格图显然是平面图。因此v-e+f=连通块数+1。
e就是1x2格子的个数,f就是2x2格子的个数+1,v就是1x1格子的个数。可以假想刚开始所有格子都是可用的,然后删掉一个格子后的变化,可以二维数点解决。
注意如果询问的矩形区域包含怪兽经过的所有格子,那么怪兽经过的所有格子的外围一圈格子会形成一个新的面,特判即可。
复杂度 O ( n log n ) O(n\log n) O(nlogn)。
似乎t3,t4不难,但是我是丝薄。我只会打暴力。
感觉效率好低啊
其实写博客也算一种放松吧
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define db double
#define mp make_pair
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
int R,C,n,m,X,Y;
int X3,X4,Y3,Y4;
int bit[200005][5];
ll res[100005];
map<pair<int,int>,int>id;
struct node{
int x,type,id,val;
};
struct node2{
int x,type;
};
vector<node>v[200005];
vector<node2>g[200005];
string s;
void add(int x,int y,int type){
if(!x||!y)return;
g[x].pb({y,type});
}
void Add(int x,int y,int type,int id,int val){
if(!x||!y)return;
v[x].pb({y,type,id,val});
}
void add2(int X,int Y,int X2,int Y2,int type,int id,int val){
if(X>X2||Y>Y2)return;
Add(X2,Y2,type,id,val),Add(X-1,Y2,type,id,-val),Add(X2,Y-1,type,id,-val),Add(X-1,Y-1,type,id,val);
}
int V(int x,int y){
return id.find(mp(x,y))==id.end();
}
void del(int x,int y){
if(!V(x,y))return;
add(x,y,1);
if(V(x,y+1))add(x,y,2);
if(V(x,y-1))add(x,y-1,2);
if(V(x+1,y))add(x,y,3);
if(V(x-1,y))add(x-1,y,3);
if(V(x-1,y-1)&&V(x-1,y)&&V(x,y-1)&&V(x,y))add(x-1,y-1,4);
if(V(x-1,y)&&V(x-1,y+1)&&V(x,y)&&V(x,y+1))add(x-1,y,4);
if(V(x,y)&&V(x,y+1)&&V(x+1,y)&&V(x+1,y+1))add(x,y,4);
if(V(x,y-1)&&V(x,y)&&V(x+1,y-1)&&V(x+1,y))add(x,y-1,4);
id[mp(x,y)]=1;
}
void upd(int x,int type,int z){for(;x<=C;x+=x&-x)bit[x][type]+=z;}
int ask(int x,int type){int tot(0);for(;x;x-=x&-x)tot+=bit[x][type];return tot;}
int main(){
// freopen("data.in","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>R>>C>>n>>m>>X>>Y;del(X,Y);if(n)cin>>s;X3=X4=X,Y3=Y4=Y;
for(int i=0;i<n;i++){
if(s[i]=='N')X--;else if(s[i]=='S')X++;
else if(s[i]=='W')Y--;else Y++;
X3=min(X3,X),X4=max(X4,X),Y3=min(Y3,Y),Y4=max(Y4,Y);
del(X,Y);
}
for(int i=1;i<=m;i++){
int X,Y,X2,Y2;
cin>>X>>Y>>X2>>Y2;
if(X<X3&&X4<X2&&Y<Y3&&Y4<Y2)res[i]++;
add2(X,Y,X2,Y2,1,i,-1),add2(X,Y,X2,Y2-1,2,i,1),add2(X,Y,X2-1,Y2,3,i,1),add2(X,Y,X2-1,Y2-1,4,i,-1);
}for(int i=1;i<=R;i++){
for(auto x:g[i])upd(x.x,x.type,1);
for(auto x:v[i]){
res[x.id]+=x.val*ask(x.x,x.type);
}
}for(int i=1;i<=m;i++){
cout<<res[i]+1<<"\n";
}
}