UTR #1摸魚解題報告
UTR #1摸魚解題報告
前言
最近刷uoj題,感覺古代大佬們都好強。。。
vfk的資料
連結
題解
一個普通的排序題,直接貼程式碼了。
\(Code\)
#include <bits/stdc++.h> using namespace std; int n; struct ZFC{ string s; int L; }s[10005]; bool cmp(ZFC A,ZFC B){ if(A.L==B.L) return A.s<B.s; return A.L<B.L; } int main(){ cin>>n; for(int i=1;i<=n;++i) { cin>>s[i].s; s[i].L=s[i].s.length(); } sort(s+1,s+1+n,cmp); for(int i=1;i<=n;++i) cout<<s[i].s<<endl; return 0; }
pyx的難題
連結
題解
如果已知優先順序,然後模仿整個過程是\(O(nlogn)\)的。
於是不難想到一個二分答案的\(O(nlog^{2}n)\)的做法。然而過不了。
然後我就卡在這了。。。
“第一問的二分是建立在單調性上的,而有單調性的題,往往可以試著利用掃描的方法去優化。”(題解原話)
感覺這個思路並不新,但經常會忘記有這種方向。。然而確實是很實用的一種思路。
然後把二分換成掃描就降了一個log下來,就能過了。
\(Code\)
#include <bits/stdc++.h> #define LL long long using namespace std; const int N=3e5+10; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void print(LL x){ if(x>9) print(x/10); putchar(x%10+'0'); } int n; LL sss,ttt; struct node{ int t,s,p,id,v; LL L; }a[N]; bool cmp(node A,node B){ return A.p<B.p; } bool cmp2(node A,node B){ return A.t<B.t; } bool cmp3(node A,node B){ return A.id<B.id; } map<int,int> num,pi; priority_queue< pair<int,int> > Q; void J(LL l,LL r,int pp){ int x=num[pp]; if(l<sss) l=sss; if(r>ttt) r=ttt; if(l<=r) a[x].L+=r-l+1; } LL ans[N]; int main(){ pair<int,int> z; n=read(); for(int i=1;i<=n;++i) { a[i].t=read();a[i].s=read();a[i].p=read(); a[i].id=i; if(a[i].p==-1) sss=a[i].t; } scanf("%lld",&ttt);--ttt; sort(a+1,a+1+n,cmp2); for(int i=1;i<=n;++i){ num[a[i].p]=i;a[i].v=i; } LL now=0,tt; for(int i=1;i<=n;++i){ while(now<a[i].t&&(!Q.empty())){ z=Q.top();Q.pop(); tt=min((LL)z.second,(LL)a[i].t-now); J(now,now+tt-1,z.first); now=now+tt;z.second=z.second-tt; if(z.second) Q.push(z); } if(now<a[i].t) now=a[i].t; Q.push(make_pair(a[i].p,a[i].s)); } while(!Q.empty()){ z=Q.top();Q.pop(); tt=z.second; J(now,now+tt-1,z.first); now=now+tt; } sort(a+1,a+1+n,cmp); LL w=0;int y; for(int i=1;i<=n;++i){ w=w+a[i].L; y=max(1,a[i].p+1); if(num[y]) continue; if(w==a[1].s) { a[1].p=y;break; } } cout<<a[1].p<<endl; num[a[1].p]=num[-1];a[1].v=num[-1]; for(int i=1;i<=n;++i) { y=a[i].v; while(i!=a[i].v){ swap(a[i],a[y]); y=a[i].v; } } now=0; for(int i=1;i<=n;++i){ while(now<a[i].t&&(!Q.empty())){ z=Q.top();Q.pop(); tt=min((LL)z.second,(LL)a[i].t-now); now=now+tt;z.second=z.second-tt; if(z.second) Q.push(z); else{ ans[a[num[z.first]].id]=now; } } if(now<a[i].t) now=a[i].t; Q.push(make_pair(a[i].p,a[i].s)); } while(!Q.empty()){ z=Q.top();Q.pop(); tt=z.second; now=now+tt; ans[a[num[z.first]].id]=now; } for(int i=1;i<=n;++i) { print(ans[i]);putchar(' '); } puts(""); return 0; }
ydc的大樹
連結
題解
這道題要用到樹的中心的概念。
樹的任何一個點的最遠點一定是某條直徑的端點。通過這個性質可以\(O(n)\)找直徑。
樹的直徑可能有多個(這個顯然,參考菊花樹)。
取某條直徑,找到直徑的最中間的點,這個點不一定是樹的節點,也可能是邊上的某點,記這個點是樹的中心。
有一個性質:任何一個點走到最遠點一定經過中心。
由於中心可以在邊上,那樣的話那條邊的兩個端點就必然被經過了。
然後再這道題中,如果我們把中心或中心所在邊上的某端點取出來作為根,就會有神奇的性質。
所有黑點到它的好朋友的路徑一定經過根節點。
顯然,如果把一條路徑從根節點分成兩段,第一段就是走到根,第二段就是找個最深黑點走。
然後這題就變成了一個大討論題。。
首先我們考慮如果最後答案是0,那麼方案數一定是n-m。
然後我們只考慮能讓黑點不高興的情況。
如果斷點是根,這個情況挺好寫的不說了。
若最深黑點分佈在至少3顆子樹中,我們只需考慮每個白點的子樹內黑點數即可。
若最深黑點分佈在恰好2顆子樹中,沒有最深黑點的子樹像第一種情況來就好,然後剩餘兩顆子樹之間再討論。
(由於以上兩種資料聽特殊的,似乎uoj裡資料沒有上面兩種情況)
然後只有一顆子樹內有最深黑點時,在這顆子樹內的黑點要找的其他“最深點”要另外再找一遍。
如果斷點在這顆子樹中,我們只需看它是否覆蓋到所有最深黑點進行討論。
如果斷點在其他子樹中,我們要找到次深黑點再討論,具體不贅述了,看程式碼吧。
\(Code\)
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+10;
const int INF=1e9;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(LL x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
int n,m,cnt=1;
int col[N],bl[N],dis[N],hed[N],las[N];
struct edge{
int r,nxt,w;
}e[N<<1];
void insert(int u,int v,int w){
e[++cnt].r=v;e[cnt].nxt=hed[u];hed[u]=cnt;e[cnt].w=w;
}
int rt;
int q[N];
void dij(){
int l=1,r=1;q[1]=rt;
fill_n(dis,N,INF);
dis[rt]=0;
while(l<=r){
int y=q[l++];
for(int i=hed[y];i;i=e[i].nxt){
if(dis[e[i].r]>dis[y]+e[i].w){
las[e[i].r]=y;
dis[e[i].r]=dis[y]+e[i].w;
q[++r]=e[i].r;
}
}
}
return;
}
int mxd[N],fa[N],dep[N];
void dfs(int x){
if(col[x]) mxd[x]=dep[x];
for(int i=hed[x];i;i=e[i].nxt){
if(fa[x]!=e[i].r){
fa[e[i].r]=x;
dep[e[i].r]=dep[x]+e[i].w;
dfs(e[i].r);
mxd[x]=max(mxd[x],mxd[e[i].r]);
}
}
}
int mx=0;
int ans1=0,ans2=0;
void upd(int x){
if(x<=0) return;
if(x>ans1){ans1=x;ans2=1;}
else if(x==ans1) ++ans2;
}
int sz[N],son[N];
void getval(int x){
sz[x]=col[x];
if(col[x]==1&&dep[x]==mx) son[x]=1;
for(int i=hed[x];i;i=e[i].nxt){
if(e[i].r!=fa[x]){
getval(e[i].r);
sz[x]+=sz[e[i].r];
son[x]+=son[e[i].r];
}
}
}
void DP(int x,int op,int y,int z){
for(int i=hed[x];i;i=e[i].nxt){
if(e[i].r!=fa[x]){
DP(e[i].r,op,y,z);
}
}
if(col[x]==0){
if(op==3){upd(sz[x]);return;}
if(op==2){
if(son[x]==son[y]) upd(sz[x]+m-sz[y]);
else upd(sz[x]);
return;
}
if(op==1){
if(son[x]==son[y]) upd(sz[x]+sz[z]);
else upd(sz[x]);
return;
}
}
}
int main(){
int u,v,w;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
bl[i]=read();
col[bl[i]]=1;
}
for(int i=1;i<n;++i){
u=read();v=read();w=read();
insert(u,v,w);
insert(v,u,w);
}
rt=bl[1];
dij();
for(int i=1;i<=m;++i){
if(dis[bl[i]]>dis[rt]) rt=bl[i];
}
dij();
u=rt;v=rt;
for(int i=1;i<=m;++i){
if(dis[bl[i]]>dis[v]) v=bl[i];
}
double D=dis[v]*1.0/2;
while(dis[las[v]]>=D) v=las[v];
rt=v;
dfs(rt);
for(int i=1;i<=m;++i) mx=max(mx,mxd[bl[i]]);
int k=0;
for(int i=hed[rt];i;i=e[i].nxt) if(mxd[e[i].r]==mx) ++k;
if(k>=3) k=3;
ans1=0;ans2=n-m;
if(col[rt]==0)upd(m);
getval(rt);
if(k==2){
u=0;v=0;
for(int i=hed[rt];i;i=e[i].nxt) {
if(mxd[e[i].r]==mx){
if(!u) u=e[i].r;
else v=e[i].r;
}
}
}
for(int i=hed[rt];i;i=e[i].nxt) {
if(k==3)DP(e[i].r,3,e[i].r,0);
if(k==2&&mxd[e[i].r]!=mx) DP(e[i].r,3,e[i].r,0);
if(k==2&&mxd[e[i].r]==mx) DP(e[i].r,1,e[i].r,(e[i].r^u^v));
if(k==1&&mxd[e[i].r]==mx) DP(e[i].r,2,e[i].r,0);
}
if(k==1){
u=0;v=0;
for(int i=hed[rt];i;i=e[i].nxt) {
if(mxd[e[i].r]==mx){
u=e[i].r;
}
}
v=mx;
mx=0;
for(int i=hed[rt];i;i=e[i].nxt){
if(mxd[e[i].r]!=v){
mx=max(mx,mxd[e[i].r]);
}
}
k=0;
for(int i=hed[rt];i;i=e[i].nxt) if(mxd[e[i].r]==mx) ++k;
if(mx>0){
if(k==1){
for(int i=hed[rt];i;i=e[i].nxt){
if(mxd[e[i].r]<mx) DP(e[i].r,3,e[i].r,0);
}
getval(rt);
for(int i=hed[rt];i;i=e[i].nxt){
if(mxd[e[i].r]==mx) DP(e[i].r,1,e[i].r,u);
}
}
else{
for(int i=hed[rt];i;i=e[i].nxt){
if(mxd[e[i].r]<=mx) DP(e[i].r,3,e[i].r,0);
}
}
}
}
printf("%d %d\n",ans1,ans2);
return 0;
}