P1084 [NOIP2012 提高组] 疫情控制 解题报告
题解 P1084 [NOIP2012 提高组] 疫情控制
开始前
这题太TM毒瘤了,太自信以为可以不看题解切,结果越想越不对劲,后来调出来90ptsTLE,就去求救了,最后修正了复杂度。总共写了不知道几个小时
思路
考虑备选时间 \(n_1<n_2\) 如果 \(n_1\) 可以,则 \(n_2\) 肯定可以,则知damn(ans)单调,则对答案二分答案 。
相对check函数来说,其他的地方如 树上倍增(是这个名字吗?)啥啥啥的显得容易很多,手搓一点hack就能调了。我的程序性能很差,有的地方用极大的空间换了时间。
树上倍增
还是讲一下树上倍增部分吧。
void init(){//肯定没问题
for(int j=1;j<20;++j){
for(int i=2;i<=n;++i){//祖先是谁 到祖先多少时间
if(1<=dep[i]-(1<<j)){
fa[i][j]=fa[fa[i][j-1]][j-1];
tim[i][j]=tim[i][j-1]+tim[fa[i][j-1]][j-1];
}
}
}
}
\(fa[i][j]\) 表示从i往上jump \(2^j\) 步的祖先,\(fa[i][0]\) 是父节点,惊喜的发现我的 \(fa\) 里不想要的地方都是 \(0\)
\(tim[i][j]\) 类似,从从i往上jump \(2^j\) 步的花费时间,也发现不要的地方为 \(0\)
代码
太感人了,重工业题
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+10;
using ll=long long;
#define pii pair<int,int>
struct army{
int id,t;
bool operator<(army y)const{
return t>y.t;
}
};
struct Edge{
int v,nxt;
ll w;
}edge[maxn*2];
ll sumw=0,w[maxn];
int n,m,head[maxn],edgetot,pos[maxn],pos_[maxn];
ll dep[maxn],fa[maxn][20],tim[maxn][20]/*祖先是谁 到祖先多少时间 */;
int build[maxn],leaf[maxn],leaftot,armytime[maxn],trcolor[maxn]/*某个节点所属的分支*/,colortot,colortoson[maxn]/*某颜色分支所属的 1的子节点*/;
void add(int u,int v,int w){
edge[++edgetot]=(Edge){v,head[u],w};
head[u]=edgetot;
}
void dfs1(int u,int f){//初始化
dep[u]=dep[f]+1;
bool op=0;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v,w=edge[i].w;
if(v==f)continue;
fa[v][0]=u;
tim[v][0]=w;
dfs1(v,u);
op=1;
}
if(!op)leaf[u]=++leaftot;
}
void init(){//肯定没问题
for(int j=1;j<20;++j){
for(int i=2;i<=n;++i){//祖先是谁 到祖先多少时间
if(1<=dep[i]-(1<<j)){
fa[i][j]=fa[fa[i][j-1]][j-1];
tim[i][j]=tim[i][j-1]+tim[fa[i][j-1]][j-1];
}
}
}
}
void dfs2(int u,int f){
if(build[u])return;
build[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(v!=f)dfs2(v,u);
}
}
void dfs3(int u,int f,int c){
trcolor[u]=c;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(v!=f)dfs3(v,u,c);
}
}
bool cmp(int A,int B){
return w[A]<w[B];
}
bool cmp1(int A,int B){
return armytime[A]<armytime[B];
}
priority_queue<army>am[maxn];//每个1的子节点的可移动军队
priority_queue<army>xz;//闲置暂存
int q[maxn],qtot=0,node[maxn],nodetot;
int get(int u,int f){//要改
int cnt=0;
if(leaf[u])return (build[u]?0:1);
if(build[u])return 0;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(v==f)continue;
cnt+=get(v,u);
}
return cnt;
}
bool judge(int time){
nodetot=0,qtot=0,colortot=0,leaftot=0;
w[0]=INT_MAX;
for(int i=1;i<=n;++i){//清空 O(n)
while(am[i].size())am[i].pop();
build[i]=0;
armytime[i]=0;
node[i]=0;
q[i]=0;
pos[i]=pos_[i];
}
while(xz.size())xz.pop();//O(n)
for(int i=head[1];i;i=edge[i].nxt){//初始化 O(n)
int v=edge[i].v;
w[v]=edge[i].w;
dfs3(v,1,++colortot);
colortoson[colortot]=v;
}
for(int i=1;i<=m;++i){//O(n+m)
int f=pos[i],t=time;
for(int j=19;j>=0;--j){
if(fa[f][j]!=1&&t>=tim[f][j]&&fa[f][j]!=0){
t-=tim[f][j],f=fa[f][j];
}
}
if(t>tim[f][0]){//还有多的时间
armytime[i]=t-tim[f][0];//军队剩余时间 先走到1
am[f].push({i,armytime[i]});
f=fa[f][0];
}else if(!build[f]){//没时间了 最多跳到 1的子节点
dfs2(f,fa[f][0]);
}
pos[i]=f;//i这个军队的位置
}
for(int i=head[1];i;i=edge[i].nxt)//O(n)
{
int v=edge[i].v;
if(am[v].size()&&get(v,1)){//仍未染
int v_=am[v].top().id;
if(armytime[v_]<tim[v][0]){//回不去了
am[v].pop();
dfs2(v,1);
}
}
while(am[v].size()){
xz.push(am[v].top());
am[v].pop();
}
}
for(int i=head[1];i;i=edge[i].nxt){//O(n)
int v=edge[i].v;
if(get(v,1))node[++nodetot]=v;
}
//剩下的全部是子树染了的、回的去的、总之真正闲置的军队
sort(node+1,node+1+nodetot,cmp);//按消费从小到大 O(nlogn)
int nw=0;
for(int i=1;i<=nodetot;++i){//把染完了的,可以回家的用掉 O(n)
while(xz.size()&&xz.top().t<w[node[i]])xz.pop();
if(xz.size()){
xz.pop();
dfs2(node[i],1);
}
}
for(int i=2;i<=n;++i)if(leaf[i]&&!build[i])return 0;//O(n)
return 1;
}
int main(){
// ios::sync_with_stdio(0),cin.tie(0);
// freopen("10.in","r",stdin);
// freopen("10.out","w",stdout);
cin>>n;
for(int i=1;i<n;++i){
int u,v,w;
cin>>u>>v>>w;
sumw+=w;
add(u,v,w);add(v,u,w);
}
dfs1(1,0);
init();
// for(int i=1;i<=n;++i)for(int j=0;j<=3;++j)cout<<tim[i][j]<<" \n"[j==3];
cin>>m;
for(int i=1;i<=m;++i)cin>>pos_[i];
ll L=0,R=sumw*2,ans=-1;//cout<<judge(3);
while(L<=R){
int mid=L+R>>1;
if(judge(mid))ans=mid,R=mid-1;
else L=mid+1;
}
cout<<ans;
return 0;
}
/*
6
2 1 7
3 1 5
4 2 1
5 4 1
6 1 1
3
5 6 4
*///9
/*
5
1 2 3
1 3 2
2 4 2
2 5 3
2
4 5
//7
/*
1
(1)/\(2)
2 3
\(3)
4
*/
/*
10
2 1 3
2 3 4
1 4 7
5 1 9
6 1 2
4 7 9
7 8 8
9 8 8
1 10 2
5
2 8 5 4 2
*/
//9
/*
50
1 2 7528
3 2 3807
3 4 4184
5 2 5932
5 6 6827
7 4 392
8 5 5041
7 9 2394
6 10 999
1 11 4033
12 9 6303
13 1 5129
10 14 1184
3 15 2326
15 16 374
10 17 5939
11 18 7425
19 9 7678
20 4 1731
21 10 6589
22 15 6826
23 2 8624
17 24 6359
3 25 8616
14 26 2558
18 27 9808
28 22 3697
29 24 7734
2 30 6093
31 5 5374
32 27 5515
24 33 9738
10 34 271
35 25 32
36 13 1976
37 36 6419
38 28 4066
1 39 5951
16 40 7323
41 23 9626
42 28 8613
43 8 5281
2 44 6810
36 45 1819
5 46 9556
47 32 3061
34 48 1940
13 49 4641
11 50 9574
5
42 49 17 43 20
*/
//27815
完结
凤头猪肚豹尾

浙公网安备 33010602011771号