题目:https://www.luogu.org/problemnew/show/P1084
5个月前曾经写过一次,某个上学日的深夜,精疲力竭后只有区区10分,从此没管...
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long using namespace std; priority_queue< pair<int,int> >q1,q2; int const MAXN=50005; int n,m,head[MAXN],ct,ans,fa[MAXN],sid[MAXN],lf,lef[MAXN],gr[MAXN]; ll l,r; bool vis[MAXN],in[MAXN]; struct N{ int to,next,w; N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {} }edge[MAXN<<1]; struct E{ int st,pos; ll rest; }am[MAXN]; void add(int x,int y,int z) { edge[++ct]=N(y,head[x],z);head[x]=ct; edge[++ct]=N(x,head[y],z);head[y]=ct; } void ps(int x) { int nw=am[x].st; while(fa[nw]!=1&&am[x].rest-sid[nw]) { am[x].rest-=sid[nw]; nw=fa[nw]; } if(fa[nw]==1&&am[x].rest>=2*sid[nw])am[x].pos=1,am[x].rest-=sid[nw]; else am[x].pos=nw; } void init(int x,int f,int g,int w)//fa,gr,lef,sid { int t=0; fa[x]=f;sid[x]=w; if(g==1)gr[x]=x; else gr[x]=g; for(int i=head[x],u;i;i=edge[i].next) { u=edge[i].to; if(u==f)continue; init(u,x,gr[x],edge[i].w);t++; } if(!t)lef[++lf]=x; } void dfs(int x) { vis[x]=1; for(int i=head[x],u;i;i=edge[i].next) if(edge[i].to!=fa[x])dfs(edge[i].to); } bool pd(ll mid) { // printf("mid=%d ",mid); memset(vis,0,sizeof vis); memset(in,0,sizeof in); while(q1.size())q1.pop(); while(q2.size())q2.pop(); for(int i=1;i<=m;i++) { am[i].rest=mid; ps(i); if(am[i].pos!=1)dfs(am[i].pos); q1.push(make_pair(-am[i].rest,i)); } // for(int i=1;i<=m;i++) // printf("am[%d].pos=%d ",i,am[i].pos); for(int i=1;i<=lf;i++) if(!vis[lef[i]]&&!in[gr[lef[i]]]) { q2.push(make_pair(-sid[gr[lef[i]]],gr[lef[i]])); in[gr[lef[i]]]=1; } // printf("q1:%d q2:%d ",q1.size(),q2.size()); while(q1.size()&&q2.size()) { int x=q1.top().second;q1.pop();//am int y=q2.top().second;q2.pop();//gr // printf("x=%d y=%d ",x,y); while(am[x].rest<sid[gr[y]]&&q1.size())x=q1.top().second,q1.pop(); if(am[x].rest<sid[gr[y]]&&!q1.size())return 0; } if(q2.size())return 0; else return 1; } int main() { scanf("%d",&n); for(int i=1,x,y,z;i<n;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z);r+=z; } init(1,0,1,0); // for(int i=1;i<=lf;i++) // printf("lef[%d]=%d ",i,lef[i]); scanf("%d",&m); for(int i=1;i<=m;i++) scanf("%d",&am[i].st); ans=-1; while(l<=r) { ll mid=((l+r)>>1); // cout<<ans<<endl; if(pd(mid))ans=mid,r=mid-1; else l=mid+1; } printf("%d",ans); return 0; }
这几天又重新写它了,自信码力已和当时不可同日而语,于是又写了一遍,然而仅仅20分,改了改成了30分...
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> using namespace std; typedef long long ll; int const xn=50005; int n,m,cnt,hd[xn],ct,to[xn<<1],nxt[xn<<1],w[xn<<1],rs[xn],lf[xn],rk[xn]; int f[xn][20],son[xn],dep[xn],num[xn]; ll dis[xn],sum,ans; bool vis[xn],use[xn]; priority_queue<int>q; vector<int>v[xn]; struct N{ int st,pos; ll tim; bool operator < (const N &y) const {return tim<y.tim;} }a[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;} int dfs(int x,int fa,int r) { int ret=0,fl=0; f[x][0]=fa; for(int i=1;i<=16;i++)f[x][i]=f[f[x][i-1]][i-1]; for(int i=hd[x],u;i;i=nxt[i]) { if((u=to[i])==fa)continue; fl=1; dis[u]=dis[x]+w[i]; dep[u]=dep[x]+1; if(x==1)lf[u]+=dfs(u,x,u),son[++cnt]=u; else ret+=dfs(u,x,r); } if(!fl)ret=1,rs[x]=r; return ret; } bool cmp(int a,int b){return dis[son[a]]>dis[son[b]];} void dfs2(int x) { bool fl=0; for(int i=hd[x],u;i;i=nxt[i]) if((u=to[i])!=f[x][0])fl=1,dfs2(u); if(!fl)num[rs[x]]++; } bool ck(int mid) { memset(vis,0,sizeof vis); memset(num,0,sizeof num); memset(use,0,sizeof use); for(int i=1;i<=cnt;i++)v[i].clear(); while(q.size())q.pop(); for(int i=1;i<=m;i++)a[i].pos=0; for(int i=1;i<=m;i++) { int x=a[i].st; ll ret=mid; for(int j=16;j>=0;j--) if(f[x][j]>1&&dis[x]-dis[f[x][j]]<=ret) ret-=dis[x]-dis[f[x][j]],x=f[x][j]; if(dep[x]>1||(dep[x]==1&&ret<dis[x]))dfs2(x); else { a[i].pos=x; a[i].tim=ret-dis[x]; q.push(i); //x:1~n v[x].push_back(i); // printf("in:%d ",i);//tim从大到小 } } for(int i=1;i<=cnt;i++) if(num[son[i]]==lf[son[i]])vis[i]=1;//i != son[i] // vis[1~cnt] for(int i=1;i<=cnt;i++) { int x=rk[i];//1~cnt // printf("vis[%d]=%d ",son[x],vis[x]); if(vis[x])continue; if(!q.size())return 0; int k=q.top(); q.pop(); while(use[k])k=q.top(),q.pop(); if(a[k].tim<dis[son[x]]) { int us=-1; for(int j=0;j<v[son[x]].size();j++) { int nw=v[son[x]][j]; if(!use[nw]&&(us==-1||a[nw].tim<a[us].tim))us=nw; } if(us==-1)return 0; else use[us]=1,q.push(k); } vis[x]=1; // printf("%d -> %d ",i,son[x]); } // printf("return 1 "); return 1; } int main() { n=rd(); for(int i=1,x,y,z;i<n;i++) { x=rd(); y=rd(); z=rd(); add(x,y,z); add(y,x,z); sum+=z; } m=rd(); for(int i=1;i<=m;i++)a[i].st=rd(); dfs(1,0,0); for(int i=1;i<=cnt;i++)rk[i]=i; sort(rk+1,rk+cnt+1,cmp);//rk -> 1~cnt // for(int i=1;i<=cnt;i++)printf("dis[%d]=%lld rk[%d]=%d ",son[i],dis[son[i]],i,rk[i]); ll l=0,r=sum; ans=-1; while(l<=r) { ll mid=((l+r)>>1ll); // printf("l=%lld r=%lld mid=%lld ",l,r,mid); if(ck(mid))ans=mid,r=mid-1; else l=mid+1; } printf("%lld ",ans); return 0; }
然后又去参考了TJ...看到思路和我的一样,但是代码简洁很多...
于是改改改,然后和模仿的那篇TJ拍拍拍,居然拍出了TJ的错...又和另一篇TJ拍拍拍,大数据又有错...
不管了直接交上去,就A了...
然后发现数据生成没管军队不在根上,但第一篇TJ小数据真的错了...
和 Narh 的代码拍,大数据又有错...但是数据那么大怎么改...不管了(反正也A了)...
又练习码力了,没事不要多写什么 queue 啦, vector 啦,直接排个序就好了。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=50005; int n,m,hd[xn],ct,to[xn<<1],nxt[xn<<1],w[xn<<1],dis[xn],sum,ans; int f[xn][20],num[xn],mn[xn],cnta,cnts,st[xn]; bool vis[xn],use[xn]; struct N{ int id,tim; bool operator < (const N &y) const {return tim>y.tim;} }a[xn],son[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;} void dfs(int x,int fa,int r) { int ret=0; f[x][0]=fa; for(int i=1;i<=16;i++)f[x][i]=f[f[x][i-1]][i-1]; for(int i=hd[x],u;i;i=nxt[i]) { if((u=to[i])==fa)continue; dis[u]=dis[x]+w[i]; dfs(u,x,r); } } bool dfs2(int x) { bool fl=1,bj=1; if(vis[x])return 1; for(int i=hd[x],u;i;i=nxt[i]) { if((u=to[i])==f[x][0])continue; bj=0; bool k=dfs2(u); if(!k) { fl=0; if(x==1)son[++cnts].id=u,son[cnts].tim=dis[u]; } } if(bj)return 0; return fl; } bool ck(int mid) { memset(vis,0,sizeof vis); memset(use,0,sizeof use); memset(mn,0,sizeof mn); cnta=0; cnts=0; for(int i=1;i<=m;i++) { int x=st[i]; ll ret=mid; for(int j=16;j>=0;j--) if(f[x][j]>1&&dis[x]-dis[f[x][j]]<=ret) ret-=dis[x]-dis[f[x][j]],x=f[x][j]; if(f[x][0]>1||(f[x][0]==1&&ret<dis[x]))vis[x]=1; else { a[++cnta].id=i; a[cnta].tim=ret-dis[x];//-dis[x] if(!mn[x]||a[cnta].tim<a[mn[x]].tim)mn[x]=i;//mn[1~n]=(1~m) } } if(dfs2(1))return 1; sort(a+1,a+cnta+1); sort(son+1,son+cnts+1); for(int i=1,p=1;i<=cnts;i++) { int nw=son[i].id; if(mn[nw]&&!use[mn[nw]]){use[mn[nw]]=1; continue;}//优先用小的,不用考虑其它儿子是因为从大往小用 while(p<=cnta&&use[a[p].id])p++; if(p>cnta||a[p].tim<son[i].tim)return 0; use[a[p].id]=1; } return 1; } int main() { n=rd(); for(int i=1,x,y,z;i<n;i++) { x=rd(); y=rd(); z=rd(); add(x,y,z); add(y,x,z); sum+=z; } m=rd(); for(int i=1;i<=m;i++)st[i]=rd(); dfs(1,0,0); int l=0,r=sum; ans=-1; while(l<=r) { int mid=((l+r)>>1ll); if(ck(mid))ans=mid,r=mid-1; else l=mid+1; } printf("%d ",ans); return 0; }