打败boss的三种方法
第一种
发现只有端点更新答案更优,或者由上面的点直接继承下来,于是增开虚拟点维护答案。为了避免被卡,虚拟点需要在失效时才被用到。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5,L=1e6;
const ll INF=(1ll<<60);
int n,A,B,opt;ll dp[3][L+5],ans=INF,hhh[L+5];
int sta[3][L+5],top[3];//额外开的点
struct node {int l,r;};
vector<node> v[N+5];
vector<int> tmp;
int c[L+5],flag[4*L+5],tag[4*L+5];
void add(int x,int v) {if(!x) return;for(int i=x; i<=L; i+=i&(-i)) c[i]+=v;}
int ask(int x) {int ret=0;for(int i=x; i>=1; i-=i&(-i)) ret+=c[i];return ret;}
void chmin(ll &x,ll y) {x=min(x,y);}
int read()
{
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int findl(int l,int r,int x,int id)
{
int ret=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(v[id][mid].l<=x) l=mid+1,ret=mid;
else r=mid-1;
}
return ret;
}
int findr(int l,int r,int x,int id)
{
int ret=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(v[id][mid].r>=x) r=mid-1,ret=mid;
else l=mid+1;
}
return ret;
}
void pushdown(int k)
{
if(!tag[k]) return;
flag[k*2]=flag[k*2+1]=tag[k*2]=tag[k*2+1]=tag[k];
tag[k]=0;
}
void modity(int k,int l,int r,int x,int y,int v)
{
if(x>r||y<l) return;
if(x<=l&&r<=y) {tag[k]=v;flag[k]=v;return;}
pushdown(k);int mid=(l+r)>>1;
modity(k*2,l,mid,x,y,v);modity(k*2+1,mid+1,r,x,y,v);
flag[k]=flag[k*2]|flag[k*2+1];
}
void getall(int k,int l,int r,int x,int y)
{
if(l==r) {if(flag[k]) tmp.push_back(l);return;}
pushdown(k);int mid=(l+r)>>1;
if(x<=mid&&flag[k*2]) getall(k*2,l,mid,x,y);
if(y>mid&&flag[k*2+1]) getall(k*2+1,mid+1,r,x,y);
}
void update(int t,int x)//用t时刻的x点更新答案
{
int l=findl(0,v[t+1].size()-1,x,t+1);
int r=findr(0,v[t+1].size()-1,x,t+1);
if(l!=-1&&v[t+1][l].r>=x) hhh[x]=dp[opt][x],modity(1,1,L,x,x,1);
else
{
if(l!=-1) chmin(dp[opt^1][v[t+1][l].r],dp[opt][x]+1ll*(x-v[t+1][l].r)*A);
if(r!=-1) chmin(dp[opt^1][v[t+1][r].l],dp[opt][x]+1ll*(v[t+1][r].l-x)*B);
}
}
void pushup(int num)
{
for(int i=-1,sz=v[num].size(); i<sz; i++)
{
int l,r;
if(i==-1) l=1,r=v[num][0].l; else l=v[num][i].r,r=(i+1==sz?L:v[num][i+1].l);
tmp.clear();getall(1,1,L,l,r);
for(int it:tmp)
{
chmin(dp[opt][l],hhh[it]+1ll*(it-l)*A);
chmin(dp[opt][r],hhh[it]+1ll*(r-it)*B);
hhh[it]=dp[opt^1][it]=INF;
}
modity(1,1,L,l,r,0);
}
}
int main()
{
memset(hhh,0x3f,sizeof hhh);
n=read(),A=read(),B=read();
for(int i=1; i<=n; i++) {int num=read();while(num--) v[i].push_back(node{read(),read()});};
memset(dp[1],0x3f,sizeof dp[1]);
for(int num=1; num<n; num++)
{
if(num>1)
for(auto it:v[num])
{
if(ask(it.l)==num-1) dp[opt][it.l]=0;
if(ask(it.r)==num-1) dp[opt][it.r]=0;
//对于特殊覆盖的判断
}
pushup(num);
for(auto it:v[num])
{
if(dp[opt][it.l]!=INF) update(num,it.l),dp[opt][it.l]=INF;
if(dp[opt][it.r]!=INF) update(num,it.r),dp[opt][it.r]=INF;
}
for(auto it:v[num]) add(it.l,1),add(it.r+1,-1);
if(num==1) memset(dp[opt],0x3f,sizeof dp[opt]);opt^=1;
}
pushup(n);
for(auto it:v[n])
{
if(ask(it.l)==n-1) dp[opt][it.l]=0;
if(ask(it.r)==n-1) dp[opt][it.r]=0;
}
for(int i=1; i<=L; i++) chmin(ans,dp[opt][i]);
printf("%lld\n",ans);
return 0;
}
注:代码有锅,不能得分。
第二种
题解做法,用两种线段树滚动维护答案。代码咕。
第三种
std做法,好像是用 \(set\) 跑图论。代码还没没看懂。。。