[bzoj2117] [2010国家集训队]Crash的旅游计划

  静态信息的点分治。

  老套路,对各个重心用数据结构维护所管辖的点到它的距离。。再去重一波

  查询的时候就直接二分了。。如果数据结构用动态开点的线段树的话就可以直接在线段树上找了..不过我还是写了treap

  时间复杂度O(nlog^3n)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 using namespace std;
 6 const int maxn=100233,mxnode=maxn*20*2;
 7 struct zs{
 8     int too,pre,dis;
 9 }e[maxn<<1];int tot,last[maxn];
10 int sz[mxnode],mx[mxnode],lc[mxnode],rc[mxnode],val[mxnode],rnd[mxnode],tt;
11 int f[maxn][20],g[maxn][20],dis[maxn][20];
12 int rt[maxn<<1],st[maxn],top,tmp[maxn],size[maxn],mxdep[maxn];
13 bool del[maxn];
14 int i,j,k,n,m,V,root,kk,POI;
15
16 int ra;char rx;
17 inline int read(){
18     rx=getchar(),ra=0;
19     while(rx<‘0‘||rx>‘9‘)rx=getchar();
20     while(rx>=‘0‘&&rx<=‘9‘)ra*=10,ra+=rx-48,rx=getchar();return ra;
21 }
22
23 void getrt(int x,int fa){
24     size[x]=1,mx[x]=0;
25     for(int i=last[x];i;i=e[i].pre)if(!del[e[i].too]&&e[i].too!=fa)
26         getrt(e[i].too,x),size[x]+=size[e[i].too],mx[x]=max(mx[x],size[e[i].too]);
27     mx[x]=max(mx[x],POI-size[x]);
28     if(mx[x]<mx[root])root=x;
29 }
30 void getpoi(int x,int fa){
31     for(int i=last[x];i;i=e[i].pre)
32         if(!del[e[i].too]&&e[i].too!=fa)st[++top]=e[i].too,tmp[e[i].too]=tmp[x]+e[i].dis,getpoi(e[i].too,x);
33 }
34 inline void upd(int x){sz[x]=sz[lc[x]]+1+sz[rc[x]];}
35 inline void lturn(int &x){int R=rc[x];rc[x]=lc[R],lc[R]=x,sz[R]=sz[x],upd(x),x=R;}
36 inline void rturn(int &x){int L=lc[x];lc[x]=rc[L],rc[L]=x,sz[L]=sz[x],upd(x),x=L;}
37 void insert(int &x){
38     if(!x){x=++tt,sz[x]=1,val[x]=V,rnd[x]=rand()+(tt&rand());return;}
39     sz[x]++;
40     if(V<=val[x]){
41         insert(lc[x]);
42         if(rnd[lc[x]]<rnd[x])rturn(x);
43     }else{
44         insert(rc[x]);
45         if(rnd[rc[x]]<rnd[x])lturn(x);
46     }
47 }
48 inline int query(int x){
49     int sm=0;
50     while(x){
51         if(V<=val[x])x=lc[x];else
52         if(V>val[x])sm+=sz[lc[x]]+1,x=rc[x];
53     }
54     return sm;
55 }
56
57 void work(int x,int dep){
58     root=0,getrt(x,0),
59     st[top=1]=x,getpoi(x,0);
60     register int i;
61     for(i=1;i<=top;i++)V=tmp[st[i]],insert(rt[root+n]);
62     for(i=1;i<=top;i++)g[st[i]][dep]=rt[root+n];
63     top=tmp[root]=0,getpoi(root,0);
64     for(i=1;i<=top;i++)V=tmp[st[i]],insert(rt[root]);
65     for(i=1;i<=top;i++)f[st[i]][dep]=rt[root],dis[st[i]][dep]=tmp[st[i]];
66     f[root][dep]=rt[root];
67     del[root]=1,mxdep[root]=dep;
68     for(i=last[root];i;i=e[i].pre)if(!del[e[i].too])POI=size[e[i].too],work(e[i].too,dep+1);
69 }
70 bool check(int x,int mid){
71     V=mid;
72     int sm=query(f[x][mxdep[x]]),i;
73     for(i=1;i<mxdep[x]&&sm<kk;i++)if(mid>dis[x][i])
74         sm++,
75         V=mid-dis[x][i],
76         sm+=query(f[x][i])-query(g[x][i+1]);
77     return sm>=kk;
78 }
79
80 inline void insert(int a,int b,int c){
81     e[++tot].too=b,e[tot].dis=c,e[tot].pre=last[a],last[a]=tot;
82     e[++tot].too=a,e[tot].dis=c,e[tot].pre=last[b],last[b]=tot;
83 }
84 int main(){
85     mx[0]=1e9+233,srand(2333);
86     n=read(),kk=read();int mx=0;
87     for(i=1;i<n;i++)j=read(),k=read(),insert(j,k,read());
88     POI=n,work(1,1);
89     for(i=1;i<tot;i+=2)mx+=e[i].dis;
90     for(i=1;i<=n;i++){
91         int l=1,r=mx,mid;
92         while(l<r){
93             mid=l+r+1>>1;
94             if(check(i,mid))r=mid-1;else l=mid;
95         }
96         printf("%d\n",l);
97     }
98     return 0;
99 }

时间: 2024-11-13 12:07:30

[bzoj2117] [2010国家集训队]Crash的旅游计划的相关文章

bzoj2117 [ 2010国家集训队 ] -- 点分树+二分答案

考虑点分树. 求出每个重心所管辖的范围内的每个点到它的距离,建成点分树. 查询时二分答案,然后问题就转化为求到x的距离<=d的点的个数. 在点分树上暴力往上跑就行了,注意去重. 时间复杂度:O(nlog3n) 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 #include&l

[国家集训队]Crash的数字表格 / JZPTAB

题目描述 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a和b,LCM(a, b)表示能同时整除a和b的最小正整数.例如,LCM(6, 8) = 24. 回到家后,Crash还在想着课上学的东西,为了研究最小公倍数,他画了一张NM的表格.每个格子里写了一个数字,其中第i行第j列的那个格子里写着数为LCM(i, j).一个45的表格如下: 1 2 3 4 5 2 2 6 4 10 3 6 3 12 15 4 4 12 4 20 看着这

「luogu1829」 [国家集训队]Crash的数字表格

莫比乌斯反演推柿子,数论分块降复杂度,最后时间复杂度为O(n). 1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N=1e7+10,mod=20101009; 5 int n,m,mi; 6 ll p[N],tot; 7 ll u[N]; 8 bool isp[N]; 9 void getu(int lim){ 10 u[1]=1; 11 for(int i=2;i<=

【题解】[国家集训队]Crash的数字表格 / JZPTAB

求解\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}lcm\left ( i,j \right )\). 有\(lcm\left ( i,j \right )=\frac{ij}{gcd\left ( i,j \right )}\), 所以原本的式子转化为:\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}\frac{ij}{gcd\left ( i,j \right )}\). 注意到\(i, j\) 均为 \(gcd\left ( i,j \right

P1829 [国家集训队]Crash的数字表格 / JZPTAB

推式子太快乐啦!虽然我好蠢而且dummy和maomao好巨(划掉) 思路 莫比乌斯反演的题目 首先这题有\(O(\sqrt n)\)的做法但是我没写咕咕咕 然后就是爆推一波式子 \[ \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) \] \[ \sum_{i=1}^{n}\sum_{j=1}^{m}\frac{i\times j}{gcd(i,j)} \] 设$ gcd(i,j)=d$ \[ \sum_{d=1}^{n}d\sum_{i=1}^{\lfloor\frac

【[国家集训队]Crash的数字表格 / JZPTAB】

这道题我们要求的是 \[\sum_{i=1}^N\sum_{j=1}^Mlcm(i,j)\] 总所周知\(lcm\)的性质不如\(gcd\)优雅,但是唯一分解定理告诉我们\(gcd(i,j)\times lcm(i,j)=i\times j\) 所以很容易的可以转化成这个柿子 \[\sum_{i=1}^N\sum_{j=1}^M\frac{i\times j}{(i,j)}\] 现在开始套路了 先设两个函数 \[f(n)=\sum_{i=1}^N\sum_{j=1}^M[(i,j)==n]\ti

【[国家集训队] Crash 的文明世界】

先写一个五十分的思路吧 首先这道题有一个弱化版 [POI2008]STA-Station 相当于\(k=1\),于是就是一个非常简单的树形\(dp\)的\(up\ \ and\ \ down\)思想 但是我们现在要求的是这个柿子了 \[\sum_{j=1}^ndis(i,j)^k\] 感觉这个东西很组合数学啊,感觉这个柿子像是天生为二项式定理准备的 我们还是考虑树形\(dp\) 在第一遍\(up\)的时候,我们设\(dp[i][k]\)表示 \[\sum_{j\in{i}}dis(i,j)^k\

P4827 [国家集训队] Crash 的文明世界(第二类斯特林数+树形dp)

传送门 对于点\(u\),所求为\[\sum_{i=1}^ndis(i,u)^k\] 把后面那堆东西化成第二类斯特林数,有\[\sum_{i=1}^n\sum_{j=0}^kS(k,j)\times j!\times{dis(i,u)\choose j}\] \[\sum_{j=1}^nS(k,j)\times j!\sum_{i=0}^k{dis(i,u)\choose j}\] 于是对于每个点只要维护好\(\sum_{i=0}^k{dis(i,u)\choose j}\)就好了 因为\({n

[国家集训队2010]小Z的袜子

★★★   输入文件:hose.in   输出文件:hose.out   简单对比 时间限制:1 s   内存限制:512 MB [题目描述] 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬. 你的任务便