CF1205D Almost All
题面传送门
看到那个\(\lfloor\frac{2n^2}{9}\rfloor\)感觉很神奇。
首先考虑菊花图怎么做:
容易发现可以处理一个类似于进制的东西,让前\(\frac{n}{2}\)个为\(1\)到\(\frac{n}{2}\),让后面\(\frac{n}{2}\)个第\(i\)个是\(i\times \frac{n}{2}\),容易发现这个可以组出\(\frac{n^2}{4}\)区间。
然后考虑一条链,发现一个和菊花图类似的做法,就是选一个点,然后这个点左右两边分别凑进制就好了。
然后看上去树上也是要这么做。考虑一下树的重心,满足每个子树都不超过\(\frac{n}{2}\),然后感觉这个限制似乎是个\(\frac{n}{3}\times \frac{2n}{3}\)类似物?
指导说重心一定有一种方法划分分出两个集合满足小的大于等于\(\frac{n}{3}\),考虑分类讨论:
如果最大的大于\(\frac{n}{3}\),那么直接最大的自成一组,其它一组就好了。
如果小于等于,那么就贪心能加就加,因为一定不会比\(\frac{n}{3}\)还多\(\frac{n}{3}\)。
然后就做完了,时间复杂度\(O(n\log n)\),瓶颈在于排序。
新问题:怎么快速spj
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (1000+5)
#define M (100+5)
#define K (1000+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;vector<int> S[N];
int n,m,k,x,y,Dp[N],Si[N],fa[N],Bh,C1,C2,Ps,W[N];
I void dfs(int x,int La){fa[x]=La;Si[x]=1;for(int i:S[x]) i^La&&(dfs(i,x),Si[x]+=Si[i],Dp[x]=max(Dp[x],Si[i]));Dp[x]=max(Dp[x],n-Si[x]);}
struct Ques{int w,id;}B[N];I bool cmp(Ques x,Ques y){return x.w<y.w;}
I void Make1(int x,int La){W[x]=++C1;printf("%d %d %d\n",x,La,W[x]-W[La]);for(int i:S[x]) i^La&&(Make1(i,x),0);}
I void Make2(int x,int La){W[x]=(C2+=Ps);printf("%d %d %d\n",x,La,W[x]-W[La]);for(int i:S[x]) i^La&&(Make2(i,x),0);}
I void calc(int x){
for(int i:S[x]) B[++Bh]=(Ques){Si[i]>Si[x]?n-Si[x]:Si[i],i};sort(B+1,B+Bh+1,cmp);
for(int i=Bh;i;i--)if(Ps<=n/3) Ps+=B[i].w,Make1(B[i].id,x);else Make2(B[i].id,x);exit(0);
}
int main(){
// freopen("1.in","r",stdin);
int i;scanf("%d",&n);for(i=1;i<n;i++) scanf("%d%d",&x,&y),S[x].PB(y),S[y].PB(x);
dfs(1,0);for(i=1;i<=n;i++) if(Dp[i]<=n/2) calc(i);
}