題面:node
666:ios
重點在題意轉化:每一個數能夠乘k,代價爲k,能夠減一,代價爲1,學習
因此跑最短路便可ui
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int MAXN=1e6+100; int n,ans; char f[MAXN]; bool in[MAXN]; queue<int>q; void spfa(){ memset(f,0x3f,sizeof(f)); f[0]=1,f[1]=0; memset(in,0,sizeof(in)); q.push(1); in[1]=1; while(!q.empty()){ int x=q.front(); q.pop(); if(x-1>0){ if(f[x-1]>f[x]+1){ f[x-1]=f[x]+1; if(!in[x-1]){ in[x-1]=1; q.push(x-1); } } } for(int i=1;i*x<=n+50&&i<=50;++i){ int y=i*x; if(f[y]>f[x]+i){ f[y]=f[x]+i; if(!in[y]){ in[y]=1; q.push(y); } } } in[x]=0; } } int main(){ scanf("%d",&n); spfa(); printf("%d\n",f[n]); return 0; }
椎:spa
求treap上兩點間距離blog
咱們對全部操做離線,而後考慮把treap按中序遍歷拍到序列上,這樣這個序列的k是有序的string
求樹上兩點間的距離咱們套路地想到dis(x)+dis(y)-dis(lca(x,y))*2it
如今就是考慮如何求dis和lcaio
lca好求,就是x,y區間的最大值,這個用線段樹維護,維護最大值和最大值出現的位置class
咱們看一張圖:
這是一個treap,圓內的是權值,外面的是優先級,咱們把它拍到序列上:
不難發現求兩點的lca就是區間最大值
而後考慮dis如何求,
仍是線段樹,觀察序列咱們發現一個點到根的距離就是分別以它爲左右端點的上升序列,
可是注意不是最長的,咱們是隻要發現一個比他大的就算上,類比模擬79的T1,只要發現一個祖先智商比當前的高,就努力學習到達這個智商
好比3,2這個點,它到根的距離爲2,以他爲右端點的上升序列爲1,以他爲左端點的上升序列爲1,因此總長度爲2
也就是用線段樹維護一個單調棧
考慮如何維護,咱們已知左右區間的答案如何更新到上一個區間,
咱們以向右的上升序列爲例,其中左區間的貢獻必定會被加進來,這時看右區間,若是右區間最大值比左區間最大值小,那麼右區間沒有貢獻
若是右區間最大值大於左區間最大值,那麼在右區間查找[lmax,rmax]的長度,而後把兩段長度拼起來,這個也能夠在線段樹上查找
這樣總複雜度$O(nlogn^2)$
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=2e5+5,inf=0x3f3f3f3f; int n,sta[MAXN],top=0,pos[MAXN]; struct node{ int opt,k1,k2; }a[MAXN]; struct NODE{ int maxx,lans,rans,pmx;//區間最大值,左端點最長上升,右端點最長上升,最大值的位置 }tr[MAXN<<2]; void build(int k,int l,int r){ tr[k].maxx=-inf,tr[k].pmx=-inf; tr[k].lans=tr[k].rans=0; int mid=(l+r)>>1; if(l==r) return ; build(k<<1,l,mid),build(k<<1|1,mid+1,r); } int askl(int k,int l,int r,int val){ if(l==r) return tr[k].maxx>val; int mid=(l+r)>>1; if(val>=tr[k<<1].maxx) return askl(k<<1|1,mid+1,r,val); else return tr[k].lans-tr[k<<1].lans+askl(k<<1,l,mid,val); } int askr(int k,int l,int r,int val){ if(l==r) return tr[k].maxx>val; int mid=(l+r)>>1; if(val>=tr[k<<1|1].maxx) return askr(k<<1,l,mid,val); else return tr[k].rans-tr[k<<1|1].rans+askr(k<<1|1,mid+1,r,val); } void pushup(int k,int l,int r){ if(tr[k<<1].maxx<=tr[k<<1|1].maxx) tr[k].maxx=tr[k<<1|1].maxx,tr[k].pmx=tr[k<<1|1].pmx; else tr[k].maxx=tr[k<<1].maxx,tr[k].pmx=tr[k<<1].pmx; int mid=(l+r)>>1; tr[k].lans=tr[k<<1].lans+askl(k<<1|1,mid+1,r,tr[k<<1].maxx); tr[k].rans=tr[k<<1|1].rans+askr(k<<1,l,mid,tr[k<<1|1].maxx); } void update(int k,int l,int r,int opt,int val){ if(l==r){ tr[k].maxx=val,tr[k].pmx=l; tr[k].lans=1,tr[k].rans=1; return ; } int mid=(l+r)>>1; if(opt<=mid) update(k<<1,l,mid,opt,val); else update(k<<1|1,mid+1,r,opt,val); pushup(k,l,r); } void change(int k,int l,int r,int opt){ if(l==r){ tr[k].pmx=l; tr[k].maxx=-inf; tr[k].lans=tr[k].rans=0; return ; } int mid=(l+r)>>1; if(opt<=mid) change(k<<1,l,mid,opt); else change(k<<1|1,mid+1,r,opt); pushup(k,l,r); } pair<int,int> query_max(int k,int l,int r,int opl,int opr){//qujianmaxx if(opl<=l&&r<=opr) return make_pair(tr[k].maxx,tr[k].pmx); int mid=(l+r)>>1; pair<int,int>res=make_pair(0,0); if(opl<=mid) res=max(res,query_max(k<<1,l,mid,opl,opr)); if(opr>mid) res=max(res,query_max(k<<1|1,mid+1,r,opl,opr)); return res; } pair<int,int> queryl(int k,int l,int r,int opt,int val){ if(r<=opt) return make_pair(max(val,tr[k].maxx),askr(k,l,r,val)); int mid=(l+r)>>1; if(opt<=mid) return queryl(k<<1,l,mid,opt,val); pair<int,int>r1,r2; r1=queryl(k<<1|1,mid+1,r,opt,val); r2=queryl(k<<1,l,mid,opt,max(val,r1.first)); return make_pair(r2.first,r1.second+r2.second); } pair<int,int> queryr(int k,int l,int r,int opt,int val){ if(l>r) return make_pair(0,0); if(opt<=l) return make_pair(max(val,tr[k].maxx),askl(k,l,r,val)); int mid=(l+r)>>1; if(opt>mid) return queryr(k<<1|1,mid+1,r,opt,val); pair<int,int>r1,r2; r1=queryr(k<<1,l,mid,opt,val); r2=queryr(k<<1|1,mid+1,r,opt,max(val,r1.first)); return make_pair(r2.first,r1.second+r2.second); } int dis(int x){ int res=(x==1)?0:queryl(1,1,top,x-1,pos[x]).second; return res+queryr(1,1,top,x+1,pos[x]).second; } int query(int x,int y){ return dis(x)+dis(y)-2*dis(query_max(1,1,top,x,y).second); } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i].opt); if(a[i].opt==0){ scanf("%d%d",&a[i].k1,&a[i].k2); sta[++top]=a[i].k1; }else if(a[i].opt==1){ scanf("%d",&a[i].k1); }else{ scanf("%d%d",&a[i].k1,&a[i].k2); } } sort(sta+1,sta+top+1); top=unique(sta+1,sta+top+1)-sta-1; build(1,1,top); for(int i=1;i<=n;++i){ if(a[i].opt==0){ int p=lower_bound(sta+1,sta+top+1,a[i].k1)-sta; update(1,1,top,p,a[i].k2); pos[p]=a[i].k2; }else if(a[i].opt==1){ int p=lower_bound(sta+1,sta+top+1,a[i].k1)-sta; change(1,1,top,p); pos[p]=-inf; }else{ int p1=lower_bound(sta+1,sta+top+1,a[i].k1)-sta; int p2=lower_bound(sta+1,sta+top+1,a[i].k2)-sta; if(p1>p2) swap(p1,p2); printf("%d\n",query(p1,p2)); } } return 0; }
新的世界:
考場成功理解錯題意,覺得一個光源只能被通過一次
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define int long long using namespace std; const int MAXN=505; int n,m,a[MAXN][MAXN],dis[MAXN][MAXN],r,c,l,P,Q; bool in[MAXN][MAXN]; int dx[4]={-1,0,0,1}; int dy[4]={0,-1,1,0}; queue<pair<int,int> >que; void spfa(int x,int y){ que.push(make_pair(x,y)); memset(dis,0x3f,sizeof(dis)); dis[x][y]=0,in[x][y]=1; while(!que.empty()){ x=que.front().first,y=que.front().second; que.pop(); for(int i=0;i<4;++i){ int p=x+dx[i],q=y+dy[i]; if(p<1||p>n||q<1||q>m) continue; if(dis[p][q]>dis[x][y]+a[p][q]){ dis[p][q]=dis[x][y]+a[p][q]; if(!in[p][q]){ que.push(make_pair(p,q)); in[p][q]=1; } } } in[x][y]=0; } } signed main(){ scanf("%lld%lld",&n,&m); for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j) scanf("%lld",&a[i][j]); } scanf("%lld%lld%lld%lld%lld",&r,&c,&l,&P,&Q); spfa(r,c); /*for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ cout<<dis[i][j]<<' '; } cout<<endl; }*/ printf("%lld\n",max(0ll,l-dis[P][Q])); return 0; }
光線追蹤: