签到题 我并没有读题
显然先 O ( m ) O(m) O(m)预处理出每一步最优解,然后发现这个最优策略是一个 ρ \rho ρ形的,我们再 O ( m ) d f s O(m)dfs O(m)dfs出这个 ρ \rho ρ形来计算答案。
代码:
#include
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef long long ll;
const int N=2e6+5;
int n,m,a[N],dep[N],len,q[N],top=0,pos;
ll ans=0,val,sum[N];
void dfs(int p){
int v=(a[p]+p)%m;
if(dep[v]){
pos=dep[v];
val=sum[dep[p]]-sum[dep[v]]+a[p];
len=dep[p]-dep[v]+1;
return;
}
q[dep[v]=++top]=v,sum[dep[v]]=sum[dep[p]]+a[p];
dfs(v);
}
int main(){
n=read(),m=read();
for(ri i=0;i<m;++i)a[i]=a[i+m]=read();
for(ri i=m*2-2;~i;--i)a[i]=min(a[i],a[i+1]+1);
q[dep[0]=++top]=0,dfs(0);
if(n<=top){
while(n--)ans+=a[ans%m];
cout<<ans;
return 0;
}
ans=sum[pos],n-=pos-1;
ans+=(ll)n/len*val,n-=n/len*len;
while(n--)ans+=a[ans%m];
cout<<ans;
return 0;
}
考试肝这题去了,结果一不小心圆方树建挂了23333.
显然建一个圆方树然后将每个圆点的值用它父亲方点维护一下。
上树链剖分修改一下就完了(有靠谱的 O ( n l o g n ) d f s O(nlogn)dfs O(nlogn)dfs序维护然后并不想写)。
代码:
#include
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=1e6+5,mod=998244353;
inline void add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
int n,m,k,sig;
namespace Bit{
int bit[N];
inline int lowbit(const int&x){return x&-x;}
inline void update(const int&x,const int&v){for(ri i=x;i<=sig;i+=lowbit(i))add(bit[i],v);}
inline int query(const int&x){int ret=0;for(ri i=x;i;i^=lowbit(i))add(ret,bit[i]);return ret;}
}
namespace slpf{
int tot=0,siz[N],num[N],fa[N],dep[N],top[N],hson[N],val[N];
vector<int>e[N];
inline void addedge(int u,int v){e[u].push_back(v),e[v].push_back(u);}
void dfs1(int p){
siz[p]=1;
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==fa[p])continue;
fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
if(siz[v]>siz[hson[p]])hson[p]=v;
}
}
void dfs2(int p,int tp){
top[p]=tp,num[p]=++tot;
if(!hson[p])return;
dfs2(hson[p],tp);
for(ri i=0,v;i<e[p].size();++i)if((v=e[p][i])!=fa[p]&&v!=hson[p])dfs2(v,v);
}
inline void update(int x,int y,int v){
while(top[x]^top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
Bit::update(num[top[x]],v);
Bit::update(num[x]+1,mod-v);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
Bit::update(num[y],v);
Bit::update(num[x]+1,mod-v);
if(y>n&&fa[y])add(val[fa[y]],v);
if(y<=n)add(val[y],v);
}
inline int query(int x){return (val[x]+Bit::query(num[fa[x]]))%mod;}
inline void solve(){
dfs1(1),dfs2(1,1);
for(ri op,x,y,v;k;--k){
op=read();
switch(op){
case 0:{x=read(),y=read(),update(x,y,read());break;}
case 1:{cout<<query(read())<<'\n';break;}
}
}
}
}
namespace xrz{
int tot=0,dfn[N],low[N],fa[N];
vector<int>e[N];
inline void addedge(int u,int v){e[u].push_back(v),e[v].push_back(u);}
inline void solve(int st,int ed){
slpf::addedge(ed,++sig);
while(ed^st)ed=fa[ed],slpf::addedge(sig,ed);
}
void tarjan(int p){
dfn[p]=low[p]=++tot;
for(ri i=0,v;i<e[p].size();++i){
if(!dfn[v=e[p][i]]){
fa[v]=p,tarjan(v),low[p]=min(low[p],low[v]);
if(dfn[p]<low[v]){
++sig;
slpf::addedge(p,sig);
slpf::addedge(v,sig);
}
}
if(v==fa[p])continue;
low[p]=min(low[p],dfn[v]);
}
for(ri i=0,v;i<e[p].size();++i)if((v=e[p][i])!=fa[p]&&dfn[v]<dfn[p])solve(v,p);
}
inline void solve(){
sig=n,tarjan(1);
slpf::solve();
}
}
int main(){
n=read(),m=read(),k=read();
for(ri i=1,u,v;i<=m;++i)u=read(),v=read(),xrz::addedge(u,v);
xrz::solve();
exit(0);
return 0;
}